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 <dynamicbox_errno.h>
46 #include <dynamicbox_service.h>
47 #include <dynamicbox_buffer.h>
48 #include <dynamicbox_conf.h>
55 #include "client_life.h"
56 #include "client_rpc.h"
57 #include "buffer_handler.h"
58 #include "script_handler.h" // Reverse dependency. must has to be broken
61 * \brief Allocate this in the buffer->data.
64 DRI2Buffer *dri2_buffer;
65 unsigned int attachments[1];
73 void *data; /* Gem layer */
76 void *compensate_data; /* Check the pitch value, copy this to data */
83 dynamicbox_lock_info_t lock_info;
85 enum dynamicbox_fb_type type;
92 struct inst_info *inst;
97 tbm_bufmgr slp_bufmgr;
101 Eina_List *pixmap_list;
110 static inline dynamicbox_fb_t create_pixmap(struct buffer_info *info)
112 struct gem_data *gem;
113 dynamicbox_fb_t buffer;
119 disp = ecore_x_display_get();
124 parent = DefaultRootWindow(disp);
126 buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
128 ErrPrint("Heap: %s\n", strerror(errno));
132 gem = (struct gem_data *)buffer->data;
134 buffer->type = DBOX_FB_TYPE_PIXMAP;
136 buffer->state = DBOX_FB_STATE_CREATED;
138 gem->attachments[0] = DRI2BufferFrontLeft;
140 gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
141 gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
142 gem->depth = info->pixel_size;
146 * 32 Bits is not supported for video playing.
147 * But for the transparent background, use the 32 bits, and give up video.
149 gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
150 if (gem->pixmap == (Pixmap)0) {
151 ErrPrint("Failed to create a pixmap\n");
160 memset(&gcv, 0, sizeof(gcv));
161 gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
163 XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
168 ErrPrint("Unable to clear the pixmap\n");
174 static inline int create_gem(dynamicbox_fb_t buffer)
176 struct gem_data *gem;
179 disp = ecore_x_display_get();
181 ErrPrint("Failed to get display\n");
182 return DBOX_STATUS_ERROR_IO_ERROR;
185 gem = (struct gem_data *)buffer->data;
188 gem->data = calloc(1, gem->w * gem->h * gem->depth);
190 ErrPrint("Heap: %s\n", strerror(errno));
191 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
194 ErrPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
195 return DBOX_STATUS_ERROR_NONE;
198 DRI2CreateDrawable(disp, gem->pixmap);
200 gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
201 &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
202 if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
203 ErrPrint("Failed to get a gem buffer\n");
204 DRI2DestroyDrawable(disp, gem->pixmap);
205 return DBOX_STATUS_ERROR_FAULT;
208 * \How can I destroy this?
210 gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
211 if (!gem->pixmap_bo) {
212 ErrPrint("Failed to import BO\n");
213 DRI2DestroyDrawable(disp, gem->pixmap);
214 return DBOX_STATUS_ERROR_FAULT;
217 if (DYNAMICBOX_CONF_AUTO_ALIGN && gem->dri2_buffer->pitch != gem->w * gem->depth) {
218 gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
219 if (!gem->compensate_data) {
220 ErrPrint("Failed to allocate heap\n");
224 DbgPrint("dri2_buffer: %p, name: %p, %dx%d, pitch: %d, buf_count: %d, depth: %d, compensate: %p (%d)\n",
225 gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h,
226 gem->dri2_buffer->pitch, gem->buf_count, gem->depth, gem->compensate_data, DYNAMICBOX_CONF_AUTO_ALIGN);
228 return DBOX_STATUS_ERROR_NONE;
231 static inline void *acquire_gem(dynamicbox_fb_t buffer)
233 struct gem_data *gem;
239 gem = (struct gem_data *)buffer->data;
241 ErrPrint("GEM is not supported - Use the fake gem buffer\n");
243 if (!gem->pixmap_bo) {
244 ErrPrint("GEM is not created\n");
249 tbm_bo_handle handle;
252 ErrPrint("Already acquired. but the buffer is not valid\n");
256 handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
257 gem->data = handle.ptr;
265 * If there is a compensate canvas buffer,
268 return gem->compensate_data ? gem->compensate_data : gem->data;
271 static inline void release_gem(dynamicbox_fb_t buffer)
273 struct gem_data *gem;
275 gem = (struct gem_data *)buffer->data;
276 if (s_info.fd >= 0 && !gem->pixmap_bo) {
277 ErrPrint("GEM is not created\n");
282 if (gem->refcnt > 0) {
283 ErrPrint("Reference count is not valid %d\n", gem->refcnt);
290 if (gem->refcnt == 0) {
292 DbgPrint("S/W Gem buffer has no reference\n");
296 * Update the gem buffer using compensate data buffer if it is exists
298 if (gem->compensate_data) {
305 pixel = gem->compensate_data;
306 gem_pixel = gem->data;
307 gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
309 for (y = 0; y < gem->h; y++) {
310 for (x = 0; x < gem->w; x++) {
311 *gem_pixel++ = *pixel++;
314 gem_pixel = (int *)(((char *)gem_pixel) + gap);
318 if (gem->pixmap_bo) {
319 tbm_bo_unmap(gem->pixmap_bo);
324 } else if (gem->refcnt < 0) {
325 ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
330 static inline int destroy_pixmap(dynamicbox_fb_t buffer)
332 struct gem_data *gem;
334 gem = (struct gem_data *)buffer->data;
339 disp = ecore_x_display_get();
341 return DBOX_STATUS_ERROR_IO_ERROR;
344 DbgPrint("pixmap %lu\n", gem->pixmap);
345 XFreePixmap(disp, gem->pixmap);
348 buffer->state = DBOX_FB_STATE_DESTROYED;
350 return DBOX_STATUS_ERROR_NONE;
353 static inline int destroy_gem(dynamicbox_fb_t buffer)
355 struct gem_data *gem;
358 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
362 * Forcely release the acquire_buffer.
364 gem = (struct gem_data *)buffer->data;
366 return DBOX_STATUS_ERROR_FAULT;
369 if (s_info.fd >= 0) {
370 if (gem->compensate_data) {
371 DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
372 DbgFree(gem->compensate_data);
373 gem->compensate_data = NULL;
376 if (gem->pixmap_bo) {
377 DbgPrint("unref pixmap bo\n");
378 tbm_bo_unref(gem->pixmap_bo);
379 gem->pixmap_bo = NULL;
381 DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
383 } else if (gem->data) {
384 DbgPrint("Release fake gem buffer\n");
389 return DBOX_STATUS_ERROR_NONE;
392 static inline int load_file_buffer(struct buffer_info *info)
394 dynamicbox_fb_t buffer;
400 len = strlen(DYNAMICBOX_CONF_IMAGE_PATH) + 40;
401 new_id = malloc(len);
403 ErrPrint("Heap: %s\n", strerror(errno));
404 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
407 timestamp = util_timestamp();
408 snprintf(new_id, len, SCHEMA_FILE "%s%lf", DYNAMICBOX_CONF_IMAGE_PATH, timestamp);
410 size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
412 ErrPrint("Canvas buffer size is ZERO\n");
414 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
417 buffer = calloc(1, size);
419 ErrPrint("Failed to allocate buffer\n");
421 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
424 buffer->type = DBOX_FB_TYPE_FILE;
426 buffer->state = DBOX_FB_STATE_CREATED;
431 info->buffer = buffer;
434 DbgPrint("FILE type %d created\n", size);
435 return DBOX_STATUS_ERROR_NONE;
438 static inline int load_shm_buffer(struct buffer_info *info)
442 dynamicbox_fb_t buffer; /* Just for getting a size */
446 size = info->w * info->h * info->pixel_size;
448 ErrPrint("Invalid buffer size\n");
449 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
452 id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
454 ErrPrint("shmget: %s\n", strerror(errno));
455 return DBOX_STATUS_ERROR_FAULT;
458 buffer = shmat(id, NULL, 0);
459 if (buffer == (void *)-1) {
460 ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
462 if (shmctl(id, IPC_RMID, 0) < 0) {
463 ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
466 return DBOX_STATUS_ERROR_FAULT;
469 buffer->type = DBOX_FB_TYPE_SHM;
471 buffer->state = DBOX_FB_STATE_CREATED; /*!< Needless */
472 buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
474 len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
476 new_id = malloc(len);
478 ErrPrint("Heap: %s\n", strerror(errno));
479 if (shmdt(buffer) < 0) {
480 ErrPrint("shmdt: %s\n", strerror(errno));
483 if (shmctl(id, IPC_RMID, 0) < 0) {
484 ErrPrint("shmctl: %s\n", strerror(errno));
487 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
490 snprintf(new_id, len, SCHEMA_SHM "%d", id);
494 info->buffer = buffer;
496 return DBOX_STATUS_ERROR_NONE;
499 static inline int load_pixmap_buffer(struct buffer_info *info)
501 dynamicbox_fb_t buffer;
502 struct gem_data *gem;
508 * Before call the buffer_handler_pixmap_ref function,
509 * You should make sure that the is_loaded value is toggled (1)
510 * Or the buffer_handler_pixmap_ref function will return NULL
515 DbgPrint("Buffer is already exists, but override it with new one\n");
518 buffer = buffer_handler_pixmap_ref(info);
520 DbgPrint("Failed to make a reference of a pixmap\n");
522 return DBOX_STATUS_ERROR_FAULT;
525 len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
526 new_id = malloc(len);
528 ErrPrint("Heap: %s\n", strerror(errno));
530 buffer_handler_pixmap_unref(buffer);
531 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
537 gem = (struct gem_data *)buffer->data;
539 snprintf(info->id, len, SCHEMA_PIXMAP "%d:%d", (int)gem->pixmap, info->pixel_size);
540 DbgPrint("Loaded pixmap(info->id): %s\n", info->id);
541 return DBOX_STATUS_ERROR_NONE;
544 EAPI int buffer_handler_load(struct buffer_info *info)
547 dynamicbox_target_type_e type = DBOX_TYPE_GBAR;
550 ErrPrint("buffer handler is nil\n");
551 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
554 if (info->is_loaded) {
555 DbgPrint("Buffer is already loaded\n");
556 return DBOX_STATUS_ERROR_NONE;
559 switch (info->type) {
560 case DBOX_FB_TYPE_FILE:
561 ret = load_file_buffer(info);
563 if (script_handler_buffer_info(instance_gbar_script(info->inst)) != info && instance_gbar_buffer(info->inst) != info) {
564 type = DBOX_TYPE_DBOX;
566 info->lock_info = dynamicbox_service_create_lock(instance_id(info->inst), type, DBOX_LOCK_WRITE);
568 case DBOX_FB_TYPE_SHM:
569 ret = load_shm_buffer(info);
571 if (script_handler_buffer_info(instance_gbar_script(info->inst)) != info && instance_gbar_buffer(info->inst) != info) {
572 type = DBOX_TYPE_DBOX;
574 info->lock_info = dynamicbox_service_create_lock(instance_id(info->inst), type, DBOX_LOCK_WRITE);
576 case DBOX_FB_TYPE_PIXMAP:
577 ret = load_pixmap_buffer(info);
580 ErrPrint("Invalid buffer\n");
581 ret = DBOX_STATUS_ERROR_INVALID_PARAMETER;
588 static inline int unload_file_buffer(struct buffer_info *info)
593 new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
595 ErrPrint("Heap: %s\n", strerror(errno));
596 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
599 DbgFree(info->buffer);
602 path = util_uri_to_path(info->id);
603 if (path && unlink(path) < 0) {
604 ErrPrint("unlink: %s\n", strerror(errno));
609 return DBOX_STATUS_ERROR_NONE;
612 static inline int unload_shm_buffer(struct buffer_info *info)
617 new_id = strdup(SCHEMA_SHM "-1");
619 ErrPrint("Heap: %s\n", strerror(errno));
620 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
623 if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
624 ErrPrint("%s Invalid ID\n", info->id);
626 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
630 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
632 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
635 if (shmdt(info->buffer) < 0) {
636 ErrPrint("Detach shm: %s\n", strerror(errno));
639 if (shmctl(id, IPC_RMID, 0) < 0) {
640 ErrPrint("Remove shm: %s\n", strerror(errno));
647 return DBOX_STATUS_ERROR_NONE;
650 static inline int unload_pixmap_buffer(struct buffer_info *info)
656 new_id = strdup(SCHEMA_PIXMAP "0:0");
658 ErrPrint("Heap: %s\n", strerror(errno));
659 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
662 if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &id, &pixels) != 2) {
663 ErrPrint("Invalid ID (%s)\n", info->id);
665 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
669 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
671 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
675 * Decrease the reference counter.
677 buffer_handler_pixmap_unref(info->buffer);
681 * Just clear the info->buffer.
682 * It will be reallocated again.
688 return DBOX_STATUS_ERROR_NONE;
691 EAPI int buffer_handler_unload(struct buffer_info *info)
696 ErrPrint("buffer handler is NIL\n");
697 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
700 if (!info->is_loaded) {
701 ErrPrint("Buffer is not loaded\n");
702 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
705 switch (info->type) {
706 case DBOX_FB_TYPE_FILE:
707 dynamicbox_service_destroy_lock(info->lock_info);
708 info->lock_info = NULL;
709 ret = unload_file_buffer(info);
711 case DBOX_FB_TYPE_SHM:
712 dynamicbox_service_destroy_lock(info->lock_info);
713 info->lock_info = NULL;
714 ret = unload_shm_buffer(info);
716 case DBOX_FB_TYPE_PIXMAP:
717 ret = unload_pixmap_buffer(info);
720 ErrPrint("Invalid buffer\n");
721 ret = DBOX_STATUS_ERROR_INVALID_PARAMETER;
732 EAPI const char *buffer_handler_id(const struct buffer_info *info)
734 return info ? info->id : "";
737 EAPI enum dynamicbox_fb_type buffer_handler_type(const struct buffer_info *info)
739 return info ? info->type : DBOX_FB_TYPE_ERROR;
742 EAPI void *buffer_handler_fb(struct buffer_info *info)
744 dynamicbox_fb_t buffer;
750 buffer = info->buffer;
752 if (info->type == DBOX_FB_TYPE_PIXMAP) {
758 * For getting the buffer address of gem.
760 canvas = buffer_handler_pixmap_acquire_buffer(info);
761 ret = buffer_handler_pixmap_release_buffer(canvas);
763 ErrPrint("Failed to release buffer: %d\n", ret);
771 EAPI int buffer_handler_pixmap(const struct buffer_info *info)
774 struct gem_data *gem;
777 ErrPrint("Inavlid buffer handler\n");
781 if (info->type != DBOX_FB_TYPE_PIXMAP) {
782 ErrPrint("Invalid buffer type\n");
786 buf = (dynamicbox_fb_t)info->buffer;
788 ErrPrint("Invalid buffer data\n");
792 gem = (struct gem_data *)buf->data;
796 EAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
798 dynamicbox_fb_t buffer;
800 if (!info || !info->is_loaded) {
801 ErrPrint("Buffer is not loaded\n");
805 buffer = buffer_handler_pixmap_ref(info);
810 return acquire_gem(buffer);
813 EAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
815 dynamicbox_fb_t buffer;
816 struct gem_data *gem;
822 if (!info->is_loaded) {
823 ErrPrint("Buffer is not loaded\n");
827 buffer = info->buffer;
832 gem = (struct gem_data *)buffer->data;
833 return gem->compensate_data ? gem->compensate_data : gem->data;
837 * @return "buffer" object (Not the buffer_info)
839 EAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
841 dynamicbox_fb_t buffer;
843 if (!info->is_loaded) {
844 ErrPrint("Buffer is not loaded\n");
848 if (info->type != DBOX_FB_TYPE_PIXMAP) {
849 ErrPrint("Buffer type is not matched\n");
853 buffer = info->buffer;
857 buffer = create_pixmap(info);
859 ErrPrint("Failed to create a pixmap\n");
863 info->buffer = buffer;
866 struct pkg_info *pkg;
868 pkg = instance_package(info->inst);
870 if (instance_dbox_buffer(info->inst) == info) {
871 if (package_dbox_type(pkg) == DBOX_TYPE_BUFFER) {
874 } else if (instance_gbar_buffer(info->inst) == info) {
875 if (package_gbar_type(pkg) == GBAR_TYPE_BUFFER) {
881 for (idx = 0; idx < DYNAMICBOX_CONF_EXTRA_BUFFER_COUNT; idx++) {
882 if (instance_dbox_extra_buffer(info->inst, idx) == info) {
883 if (package_dbox_type(pkg) == DBOX_TYPE_BUFFER) {
889 if (instance_gbar_extra_buffer(info->inst, idx) == info) {
890 if (package_gbar_type(pkg) == GBAR_TYPE_BUFFER) {
900 if (create_gem(buffer) < 0) {
901 /* okay, something goes wrong */
904 } else if (buffer->state != DBOX_FB_STATE_CREATED || buffer->type != DBOX_FB_TYPE_PIXMAP) {
905 ErrPrint("Invalid buffer\n");
907 } else if (buffer->refcnt > 0) {
912 s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
919 EAPI void *buffer_handler_pixmap_find(int pixmap)
921 dynamicbox_fb_t buffer;
922 struct gem_data *gem;
930 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
931 if (!buffer || buffer->state != DBOX_FB_STATE_CREATED || buffer->type != DBOX_FB_TYPE_PIXMAP) {
932 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
933 DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
937 gem = (struct gem_data *)buffer->data;
938 if (gem->pixmap == pixmap) {
946 EAPI int buffer_handler_pixmap_release_buffer(void *canvas)
948 dynamicbox_fb_t buffer;
949 struct gem_data *gem;
955 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
958 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
959 if (!buffer || buffer->state != DBOX_FB_STATE_CREATED || buffer->type != DBOX_FB_TYPE_PIXMAP) {
960 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
964 gem = (struct gem_data *)buffer->data;
965 _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
971 if (_ptr == canvas) {
973 buffer_handler_pixmap_unref(buffer);
974 return DBOX_STATUS_ERROR_NONE;
978 return DBOX_STATUS_ERROR_NOT_EXIST;
984 * \return Return NULL if the buffer is in still uses.
985 * Return buffer_ptr if it needs to destroy
987 EAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
989 dynamicbox_fb_t buffer = buffer_ptr;
990 struct buffer_info *info;
993 if (buffer->refcnt > 0) {
994 return DBOX_STATUS_ERROR_NONE; /* Return NULL means, gem buffer still in use */
997 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1001 if (destroy_gem(buffer) < 0) {
1002 ErrPrint("Failed to destroy gem buffer\n");
1005 if (destroy_pixmap(buffer) < 0) {
1006 ErrPrint("Failed to destroy pixmap\n");
1009 if (info && info->buffer == buffer) {
1010 info->buffer = NULL;
1013 return DBOX_STATUS_ERROR_NONE;
1016 EAPI int buffer_handler_is_loaded(const struct buffer_info *info)
1018 return info ? info->is_loaded : 0;
1021 EAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
1031 EAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
1036 ErrPrint("Invalid handler\n");
1037 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1040 if (info->w == w && info->h == h) {
1041 DbgPrint("No changes\n");
1042 return DBOX_STATUS_ERROR_NONE;
1045 buffer_handler_update_size(info, w, h);
1047 if (!info->is_loaded) {
1048 DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
1049 return DBOX_STATUS_ERROR_NONE;
1052 ret = buffer_handler_unload(info);
1054 ErrPrint("Unload: %d\n", ret);
1057 ret = buffer_handler_load(info);
1059 ErrPrint("Load: %d\n", ret);
1062 return DBOX_STATUS_ERROR_NONE;
1065 EAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
1068 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1078 return DBOX_STATUS_ERROR_NONE;
1081 EAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
1088 * Only for used S/W Backend
1090 static inline int sync_for_pixmap(dynamicbox_fb_t buffer)
1096 struct gem_data *gem;
1100 if (buffer->state != DBOX_FB_STATE_CREATED) {
1101 ErrPrint("Invalid state of a FB\n");
1102 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1105 if (buffer->type != DBOX_FB_TYPE_PIXMAP) {
1106 ErrPrint("Invalid buffer\n");
1107 return DBOX_STATUS_ERROR_NONE;
1110 disp = ecore_x_display_get();
1112 ErrPrint("Failed to get a display\n");
1113 return DBOX_STATUS_ERROR_FAULT;
1116 gem = (struct gem_data *)buffer->data;
1117 if (gem->w == 0 || gem->h == 0) {
1118 DbgPrint("Nothing can be sync\n");
1119 return DBOX_STATUS_ERROR_NONE;
1122 si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
1124 ErrPrint("shmget: %s\n", strerror(errno));
1125 return DBOX_STATUS_ERROR_FAULT;
1128 si.readOnly = False;
1129 si.shmaddr = shmat(si.shmid, NULL, 0);
1130 if (si.shmaddr == (void *)-1) {
1131 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1132 ErrPrint("shmctl: %s\n", strerror(errno));
1134 return DBOX_STATUS_ERROR_FAULT;
1137 screen = DefaultScreenOfDisplay(disp);
1138 visual = DefaultVisualOfScreen(screen);
1141 * XCreatePixmap can only uses 24 bits depth only.
1143 xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
1145 if (shmdt(si.shmaddr) < 0) {
1146 ErrPrint("shmdt: %s\n", strerror(errno));
1149 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1150 ErrPrint("shmctl: %s\n", strerror(errno));
1152 return DBOX_STATUS_ERROR_FAULT;
1155 xim->data = si.shmaddr;
1156 XShmAttach(disp, &si);
1159 gc = XCreateGC(disp, gem->pixmap, 0, NULL);
1161 XShmDetach(disp, &si);
1164 if (shmdt(si.shmaddr) < 0) {
1165 ErrPrint("shmdt: %s\n", strerror(errno));
1168 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1169 ErrPrint("shmctl: %s\n", strerror(errno));
1172 return DBOX_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));
1192 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1193 ErrPrint("shmctl: %s\n", strerror(errno));
1196 return DBOX_STATUS_ERROR_NONE;
1199 EAPI void buffer_handler_flush(struct buffer_info *info)
1203 dynamicbox_fb_t buffer;
1205 if (!info || !info->buffer) {
1209 buffer = info->buffer;
1211 if (buffer->type == DBOX_FB_TYPE_PIXMAP) {
1212 if (s_info.fd > 0) {
1217 XserverRegion region;
1221 rect.width = info->w;
1222 rect.height = info->h;
1224 region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
1225 XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
1226 XFixesDestroyRegion(ecore_x_display_get(), region);
1227 XFlush(ecore_x_display_get());
1228 //PERF_MARK("XFlush");
1230 if (sync_for_pixmap(buffer) < 0) {
1231 ErrPrint("Failed to sync via S/W Backend\n");
1234 } else if (buffer->type == DBOX_FB_TYPE_FILE) {
1235 fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
1237 ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
1241 size = info->w * info->h * info->pixel_size;
1242 dynamicbox_service_acquire_lock(info->lock_info);
1243 if (write(fd, info->buffer, size) != size) {
1244 ErrPrint("Write is not completed: %s\n", strerror(errno));
1246 dynamicbox_service_release_lock(info->lock_info);
1248 if (close(fd) < 0) {
1249 ErrPrint("close: %s\n", strerror(errno));
1252 DbgPrint("Flush nothing\n");
1256 HAPI int buffer_handler_init(void)
1258 int dri2Major, dri2Minor;
1259 char *driverName, *deviceName;
1262 if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
1263 ErrPrint("DRI2 is not supported\n");
1264 return DBOX_STATUS_ERROR_NONE;
1267 if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
1268 ErrPrint("DRI2 is not supported\n");
1269 s_info.evt_base = 0;
1270 s_info.err_base = 0;
1271 return DBOX_STATUS_ERROR_NONE;
1274 if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
1275 ErrPrint("DRI2 is not supported\n");
1276 s_info.evt_base = 0;
1277 s_info.err_base = 0;
1278 return DBOX_STATUS_ERROR_NONE;
1281 if (DYNAMICBOX_CONF_USE_SW_BACKEND) {
1282 DbgPrint("Fallback to the S/W Backend\n");
1283 s_info.evt_base = 0;
1284 s_info.err_base = 0;
1285 DbgFree(deviceName);
1286 DbgFree(driverName);
1287 return DBOX_STATUS_ERROR_NONE;
1290 s_info.fd = open(deviceName, O_RDWR);
1291 DbgFree(deviceName);
1292 DbgFree(driverName);
1293 if (s_info.fd < 0) {
1294 ErrPrint("Failed to open a drm device: (%s)\n", strerror(errno));
1295 s_info.evt_base = 0;
1296 s_info.err_base = 0;
1297 return DBOX_STATUS_ERROR_NONE;
1300 drmGetMagic(s_info.fd, &magic);
1301 DbgPrint("DRM Magic: 0x%X\n", magic);
1302 if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
1303 ErrPrint("Failed to do authenticate for DRI2\n");
1304 if (close(s_info.fd) < 0) {
1305 ErrPrint("close: %s\n", strerror(errno));
1308 s_info.evt_base = 0;
1309 s_info.err_base = 0;
1310 return DBOX_STATUS_ERROR_NONE;
1313 s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
1314 if (!s_info.slp_bufmgr) {
1315 ErrPrint("Failed to init bufmgr\n");
1316 if (close(s_info.fd) < 0) {
1317 ErrPrint("close: %s\n", strerror(errno));
1320 s_info.evt_base = 0;
1321 s_info.err_base = 0;
1322 return DBOX_STATUS_ERROR_NONE;
1325 return DBOX_STATUS_ERROR_NONE;
1328 HAPI int buffer_handler_fini(void)
1330 if (s_info.fd >= 0) {
1331 if (close(s_info.fd) < 0) {
1332 ErrPrint("close: %s\n", strerror(errno));
1337 if (s_info.slp_bufmgr) {
1338 tbm_bufmgr_deinit(s_info.slp_bufmgr);
1339 s_info.slp_bufmgr = NULL;
1342 return DBOX_STATUS_ERROR_NONE;
1345 static inline dynamicbox_fb_t raw_open_file(const char *filename)
1347 dynamicbox_fb_t buffer;
1352 fd = open(filename, O_RDONLY);
1354 ErrPrint("open: %s\n", strerror(errno));
1358 off = lseek(fd, 0L, SEEK_END);
1359 if (off == (off_t)-1) {
1360 ErrPrint("lseek: %s\n", strerror(errno));
1362 if (close(fd) < 0) {
1363 ErrPrint("close: %s\n", strerror(errno));
1369 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
1370 ErrPrint("lseek: %s\n", strerror(errno));
1372 if (close(fd) < 0) {
1373 ErrPrint("close: %s\n", strerror(errno));
1379 buffer = calloc(1, sizeof(*buffer) + off);
1381 ErrPrint("Heap: %s\n", strerror(errno));
1383 if (close(fd) < 0) {
1384 ErrPrint("close: %s\n", strerror(errno));
1390 buffer->state = DBOX_FB_STATE_CREATED;
1391 buffer->type = DBOX_FB_TYPE_FILE;
1393 buffer->info = (void *)off;
1395 ret = read(fd, buffer->data, off);
1397 ErrPrint("read: %s\n", strerror(errno));
1400 if (close(fd) < 0) {
1401 ErrPrint("close: %s\n", strerror(errno));
1407 if (close(fd) < 0) {
1408 ErrPrint("close: %s\n", strerror(errno));
1414 static inline int raw_close_file(dynamicbox_fb_t buffer)
1420 static inline dynamicbox_fb_t raw_open_shm(int shm)
1422 dynamicbox_fb_t buffer;
1424 buffer = (dynamicbox_fb_t)shmat(shm, NULL, SHM_RDONLY);
1425 if (buffer == (dynamicbox_fb_t)-1) {
1426 ErrPrint("shmat: %s\n", strerror(errno));
1433 static inline int raw_close_shm(dynamicbox_fb_t buffer)
1437 ret = shmdt(buffer);
1439 ErrPrint("shmdt: %s\n", strerror(errno));
1445 static inline dynamicbox_fb_t raw_open_pixmap(unsigned int pixmap)
1447 dynamicbox_fb_t buffer;
1449 buffer = calloc(1, sizeof(*buffer) + DYNAMICBOX_CONF_DEFAULT_PIXELS);
1451 ErrPrint("Heap: %s\n", strerror(errno));
1455 buffer->state = DBOX_FB_STATE_CREATED;
1456 buffer->type = DBOX_FB_TYPE_PIXMAP;
1461 static inline int raw_close_pixmap(dynamicbox_fb_t buffer)
1467 EAPI void *buffer_handler_raw_data(dynamicbox_fb_t buffer)
1469 if (!buffer || buffer->state != DBOX_FB_STATE_CREATED) {
1473 return buffer->data;
1476 EAPI int buffer_handler_raw_size(dynamicbox_fb_t buffer)
1478 if (!buffer || buffer->state != DBOX_FB_STATE_CREATED) {
1479 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1482 return (int)buffer->info;
1485 EAPI dynamicbox_fb_t buffer_handler_raw_open(enum dynamicbox_fb_type dynamicbox_fb_type, void *resource)
1487 dynamicbox_fb_t handle;
1489 switch (dynamicbox_fb_type) {
1490 case DBOX_FB_TYPE_SHM:
1491 handle = raw_open_shm((int)resource);
1493 case DBOX_FB_TYPE_FILE:
1494 handle = raw_open_file(resource);
1496 case DBOX_FB_TYPE_PIXMAP:
1497 handle = raw_open_pixmap((unsigned int)resource);
1507 EAPI int buffer_handler_raw_close(dynamicbox_fb_t buffer)
1511 if (!buffer || buffer->state != DBOX_FB_STATE_CREATED) {
1512 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1515 switch (buffer->type) {
1516 case DBOX_FB_TYPE_SHM:
1517 ret = raw_close_shm(buffer);
1519 case DBOX_FB_TYPE_FILE:
1520 ret = raw_close_file(buffer);
1522 case DBOX_FB_TYPE_PIXMAP:
1523 ret = raw_close_pixmap(buffer);
1526 ret = DBOX_STATUS_ERROR_INVALID_PARAMETER;
1533 EAPI int buffer_handler_lock(struct buffer_info *info)
1536 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1539 if (info->type == DBOX_FB_TYPE_PIXMAP) {
1540 return DBOX_STATUS_ERROR_NONE;
1543 if (info->type == DBOX_FB_TYPE_FILE) {
1544 return DBOX_STATUS_ERROR_NONE;
1547 return dynamicbox_service_acquire_lock(info->lock_info);
1550 EAPI int buffer_handler_unlock(struct buffer_info *info)
1553 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1556 if (info->type == DBOX_FB_TYPE_PIXMAP) {
1557 return DBOX_STATUS_ERROR_NONE;
1560 if (info->type == DBOX_FB_TYPE_FILE) {
1561 return DBOX_STATUS_ERROR_NONE;
1564 return dynamicbox_service_release_lock(info->lock_info);
1567 EAPI int buffer_handler_pixels(struct buffer_info *info)
1570 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1573 return info->pixel_size;
1576 EAPI int buffer_handler_auto_align(void)
1578 return DYNAMICBOX_CONF_AUTO_ALIGN;
1581 EAPI int buffer_handler_stride(struct buffer_info *info)
1583 dynamicbox_fb_t buffer;
1584 struct gem_data *gem;
1588 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1591 switch (info->type) {
1592 case DBOX_FB_TYPE_FILE:
1593 case DBOX_FB_TYPE_SHM:
1594 stride = info->w * info->pixel_size;
1596 case DBOX_FB_TYPE_PIXMAP:
1597 buffer = info->buffer;
1599 stride = DBOX_STATUS_ERROR_INVALID_PARAMETER;
1603 gem = (struct gem_data *)buffer->data;
1605 stride = DBOX_STATUS_ERROR_INVALID_PARAMETER;
1609 if (!gem->dri2_buffer) {
1613 ErrPrint("dri2_buffer info is not ready yet!\n");
1614 stride = DBOX_STATUS_ERROR_INVALID_PARAMETER;
1618 stride = gem->dri2_buffer->pitch;
1621 stride = DBOX_STATUS_ERROR_INVALID_PARAMETER;
1630 * Only can be used by master.
1631 * Plugin cannot access the user data
1634 HAPI int buffer_handler_set_data(struct buffer_info *info, void *data)
1637 ErrPrint("Invalid handle\n");
1638 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1642 return DBOX_STATUS_ERROR_NONE;
1645 HAPI void *buffer_handler_data(struct buffer_info *info)
1648 ErrPrint("Invalid handle\n");
1655 HAPI int buffer_handler_destroy(struct buffer_info *info)
1658 dynamicbox_fb_t buffer;
1661 DbgPrint("Buffer is not created yet. info is NIL\n");
1662 return DBOX_STATUS_ERROR_NONE;
1665 EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
1666 if (buffer->info == info) {
1667 buffer->info = NULL;
1671 buffer_handler_unload(info);
1674 return DBOX_STATUS_ERROR_NONE;
1677 HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum dynamicbox_fb_type type, int w, int h, int pixel_size)
1679 struct buffer_info *info;
1681 info = malloc(sizeof(*info));
1683 ErrPrint("Heap: %s\n", strerror(errno));
1688 case DBOX_FB_TYPE_SHM:
1689 if (pixel_size != DYNAMICBOX_CONF_DEFAULT_PIXELS) {
1690 DbgPrint("SHM only supportes %d bytes pixels (requested: %d)\n", DYNAMICBOX_CONF_DEFAULT_PIXELS, pixel_size);
1691 pixel_size = DYNAMICBOX_CONF_DEFAULT_PIXELS;
1694 info->id = strdup(SCHEMA_SHM "-1");
1696 ErrPrint("Heap: %s\n", strerror(errno));
1701 case DBOX_FB_TYPE_FILE:
1702 if (pixel_size != DYNAMICBOX_CONF_DEFAULT_PIXELS) {
1703 DbgPrint("FILE only supportes %d bytes pixels (requested: %d)\n", DYNAMICBOX_CONF_DEFAULT_PIXELS, pixel_size);
1704 pixel_size = DYNAMICBOX_CONF_DEFAULT_PIXELS;
1707 info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
1709 ErrPrint("Heap: %s\n", strerror(errno));
1714 case DBOX_FB_TYPE_PIXMAP:
1715 info->id = strdup(SCHEMA_PIXMAP "0:0");
1717 ErrPrint("Heap: %s\n", strerror(errno));
1723 ErrPrint("Invalid type\n");
1728 info->lock_info = NULL;
1731 info->pixel_size = pixel_size;
1733 info->is_loaded = 0;
1735 info->buffer = NULL;