summaryrefslogtreecommitdiff
path: root/src/buffer_handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer_handler.c')
-rw-r--r--src/buffer_handler.c1765
1 files changed, 1765 insertions, 0 deletions
diff --git a/src/buffer_handler.c b/src/buffer_handler.c
new file mode 100644
index 0000000..c27eecf
--- /dev/null
+++ b/src/buffer_handler.c
@@ -0,0 +1,1765 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h> /* access */
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <Ecore.h>
+#include <Ecore_X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/XShm.h>
+
+#include <dri2.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <tbm_bufmgr.h>
+
+#include <dlog.h>
+#include <packet.h>
+#include <livebox-errno.h>
+
+#include "debug.h"
+#include "conf.h"
+#include "util.h"
+#include "instance.h"
+#include "package.h"
+#include "client_life.h"
+#include "client_rpc.h"
+#include "buffer_handler.h"
+#include "script_handler.h" // Reverse dependency. must has to be broken
+
+struct buffer {
+ enum {
+ CREATED = 0x00beef00,
+ DESTROYED = 0x00dead00
+ } state;
+ enum buffer_type type;
+ int refcnt;
+ void *info;
+ char data[];
+};
+
+/*!
+ * \brief Allocate this in the buffer->data.
+ */
+struct gem_data {
+ DRI2Buffer *dri2_buffer;
+ unsigned int attachments[1];
+ tbm_bo pixmap_bo;
+ int count;
+ int buf_count;
+ int w;
+ int h;
+ int depth;
+ Pixmap pixmap;
+ void *data; /* Gem layer */
+ int refcnt;
+
+ void *compensate_data; /* Check the pitch value, copy this to data */
+};
+
+struct buffer_info
+{
+ void *buffer;
+ char *id;
+ char *lock;
+ int lock_fd;
+
+ enum buffer_type type;
+
+ int w;
+ int h;
+ int pixel_size;
+ int is_loaded;
+
+ struct inst_info *inst;
+ void *data;
+};
+
+static struct {
+ tbm_bufmgr slp_bufmgr;
+ int evt_base;
+ int err_base;
+ int fd;
+ Eina_List *pixmap_list;
+} s_info = {
+ .slp_bufmgr = NULL,
+ .evt_base = 0,
+ .err_base = 0,
+ .fd = -1,
+ .pixmap_list = NULL,
+};
+
+static int destroy_lock_file(struct buffer_info *info)
+{
+ if (!info->inst) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!info->lock) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (close(info->lock_fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ info->lock_fd = -1;
+
+ if (unlink(info->lock) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+
+ DbgFree(info->lock);
+ info->lock = NULL;
+ return LB_STATUS_SUCCESS;
+}
+
+static int create_lock_file(struct buffer_info *info)
+{
+ const char *id;
+ int len;
+ char *file;
+ char target[3] = "pd";
+
+ if (!info->inst) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ id = instance_id(info->inst);
+ if (!id) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ len = strlen(id);
+ file = malloc(len + 20);
+ if (!file) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (script_handler_buffer_info(instance_pd_script(info->inst)) != info && instance_pd_buffer(info->inst) != info) {
+ target[0] = 'l';
+ target[1] = 'b';
+ /* target[2] = '\0'; // We already have this ;) */
+ }
+
+ snprintf(file, len + 20, "%s.%s.lck", util_uri_to_path(id), target);
+ info->lock_fd = open(file, O_WRONLY|O_CREAT, 0644);
+ if (info->lock_fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ DbgFree(file);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ info->lock = file;
+ return LB_STATUS_SUCCESS;
+}
+
+static int do_buffer_lock(struct buffer_info *buffer)
+{
+ struct flock flock;
+ int ret;
+
+ if (buffer->lock_fd < 0) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ flock.l_type = F_WRLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+ flock.l_pid = getpid();
+
+ do {
+ ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
+ if (ret < 0) {
+ ret = errno;
+ ErrPrint("fcntl: %s\n", strerror(errno));
+ }
+ } while (ret == EINTR);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static int do_buffer_unlock(struct buffer_info *buffer)
+{
+ struct flock flock;
+ int ret;
+
+ if (buffer->lock_fd < 0) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ flock.l_type = F_UNLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+ flock.l_pid = getpid();
+
+ do {
+ ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
+ if (ret < 0) {
+ ret = errno;
+ ErrPrint("fcntl: %s\n", strerror(errno));
+ }
+ } while (ret == EINTR);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct buffer *create_pixmap(struct buffer_info *info)
+{
+ struct gem_data *gem;
+ struct buffer *buffer;
+ Display *disp;
+ Window parent;
+ XGCValues gcv;
+ GC gc;
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ return NULL;
+ }
+
+ parent = DefaultRootWindow(disp);
+
+ buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+
+ buffer->type = BUFFER_TYPE_PIXMAP;
+ buffer->refcnt = 1;
+ buffer->state = CREATED;
+
+ gem->attachments[0] = DRI2BufferFrontLeft;
+ gem->count = 1;
+ gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
+ gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
+ gem->depth = info->pixel_size;
+ /*!
+ * \NOTE
+ * Use the 24 Bits
+ * 32 Bits is not supported for video playing.
+ * But for the transparent background, use the 32 bits, and give up video.
+ */
+ gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
+ if (gem->pixmap == (Pixmap)0) {
+ ErrPrint("Failed to create a pixmap\n");
+ DbgFree(buffer);
+ return NULL;
+ }
+
+ /*!
+ * \note
+ * Clear pixmap
+ */
+ memset(&gcv, 0, sizeof(gcv));
+ gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
+ if (gc) {
+ XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
+ XSync(disp, False);
+ XFreeGC(disp, gc);
+ } else {
+ XSync(disp, False);
+ ErrPrint("Unable to clear the pixmap\n");
+ }
+
+ return buffer;
+}
+
+static inline int create_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+ Display *disp;
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ ErrPrint("Failed to get display\n");
+ return LB_STATUS_ERROR_IO;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+
+ if (s_info.fd < 0) {
+ gem->data = calloc(1, gem->w * gem->h * gem->depth);
+ if (!gem->data) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ ErrPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ DRI2CreateDrawable(disp, gem->pixmap);
+
+ gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
+ &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
+ if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
+ ErrPrint("Failed to get a gem buffer\n");
+ DRI2DestroyDrawable(disp, gem->pixmap);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ /*!
+ * \How can I destroy this?
+ */
+ gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
+ if (!gem->pixmap_bo) {
+ ErrPrint("Failed to import BO\n");
+ DRI2DestroyDrawable(disp, gem->pixmap);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
+ gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
+ if (!gem->compensate_data) {
+ ErrPrint("Failed to allocate heap\n");
+ }
+ }
+
+ DbgPrint("dri2_buffer: %p, name: %p, %dx%d, pitch: %d, buf_count: %d, depth: %d, compensate: %p\n",
+ gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h,
+ gem->dri2_buffer->pitch, gem->buf_count, gem->depth, gem->compensate_data);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline void *acquire_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ if (!buffer) {
+ return NULL;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (s_info.fd < 0) {
+ ErrPrint("GEM is not supported - Use the fake gem buffer\n");
+ } else {
+ if (!gem->pixmap_bo) {
+ ErrPrint("GEM is not created\n");
+ return NULL;
+ }
+
+ if (!gem->data) {
+ tbm_bo_handle handle;
+
+ if (gem->refcnt) {
+ ErrPrint("Already acquired. but the buffer is not valid\n");
+ return NULL;
+ }
+
+ handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
+ gem->data = handle.ptr;
+ }
+ }
+
+ gem->refcnt++;
+
+ /*!
+ * \note
+ * If there is a compensate canvas buffer,
+ * use it
+ */
+ return gem->compensate_data ? gem->compensate_data : gem->data;
+}
+
+static inline void release_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ gem = (struct gem_data *)buffer->data;
+ if (s_info.fd >= 0 && !gem->pixmap_bo) {
+ ErrPrint("GEM is not created\n");
+ return;
+ }
+
+ if (!gem->data) {
+ if (gem->refcnt > 0) {
+ ErrPrint("Reference count is not valid %d\n", gem->refcnt);
+ gem->refcnt = 0;
+ }
+ return;
+ }
+
+ gem->refcnt--;
+ if (gem->refcnt == 0) {
+ if (s_info.fd < 0) {
+ DbgPrint("S/W Gem buffer has no reference\n");
+ } else {
+ /*!
+ * \note
+ * Update the gem buffer using compensate data buffer if it is exists
+ */
+ if (gem->compensate_data) {
+ register int x;
+ register int y;
+ int *gem_pixel;
+ int *pixel;
+ int gap;
+
+ pixel = gem->compensate_data;
+ gem_pixel = gem->data;
+ gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
+
+ for (y = 0; y < gem->h; y++) {
+ for (x = 0; x < gem->w; x++) {
+ *gem_pixel++ = *pixel++;
+ }
+
+ gem_pixel = (int *)(((char *)gem_pixel) + gap);
+ }
+ }
+
+ if (gem->pixmap_bo) {
+ tbm_bo_unmap(gem->pixmap_bo);
+ }
+
+ gem->data = NULL;
+ }
+ } else if (gem->refcnt < 0) {
+ ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
+ gem->refcnt = 0;
+ }
+}
+
+static inline int destroy_pixmap(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ gem = (struct gem_data *)buffer->data;
+
+ if (gem->pixmap) {
+ Display *disp;
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ return LB_STATUS_ERROR_IO;
+ }
+
+ DbgPrint("pixmap %lu\n", gem->pixmap);
+ XFreePixmap(disp, gem->pixmap);
+ }
+
+ buffer->state = DESTROYED;
+ DbgFree(buffer);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int destroy_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ if (!buffer) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ /*!
+ * Forcely release the acquire_buffer.
+ */
+ gem = (struct gem_data *)buffer->data;
+ if (!gem) {
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (s_info.fd >= 0) {
+ if (gem->compensate_data) {
+ DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
+ DbgFree(gem->compensate_data);
+ gem->compensate_data = NULL;
+ }
+
+ if (gem->pixmap_bo) {
+ DbgPrint("unref pixmap bo\n");
+ tbm_bo_unref(gem->pixmap_bo);
+ gem->pixmap_bo = NULL;
+
+ DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
+ }
+ } else if (gem->data) {
+ DbgPrint("Release fake gem buffer\n");
+ DbgFree(gem->data);
+ gem->data = NULL;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_file_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ double timestamp;
+ int size;
+ char *new_id;
+ int len;
+
+ len = strlen(IMAGE_PATH) + 40;
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ timestamp = util_timestamp();
+ snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
+
+ size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
+ if (!size) {
+ ErrPrint("Canvas buffer size is ZERO\n");
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ buffer = calloc(1, size);
+ if (!buffer) {
+ ErrPrint("Failed to allocate buffer\n");
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ buffer->type = BUFFER_TYPE_FILE;
+ buffer->refcnt = 0;
+ buffer->state = CREATED;
+ buffer->info = info;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+
+ DbgPrint("FILE type %d created\n", size);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_shm_buffer(struct buffer_info *info)
+{
+ int id;
+ int size;
+ struct buffer *buffer; /* Just for getting a size */
+ char *new_id;
+ int len;
+
+ size = info->w * info->h * info->pixel_size;
+ if (!size) {
+ ErrPrint("Invalid buffer size\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
+ if (id < 0) {
+ ErrPrint("shmget: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ buffer = shmat(id, NULL, 0);
+ if (buffer == (void *)-1) {
+ ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ buffer->type = BUFFER_TYPE_SHM;
+ buffer->refcnt = id;
+ buffer->state = CREATED; /*!< Needless */
+ buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
+
+ len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
+
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ if (shmdt(buffer) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ snprintf(new_id, len, SCHEMA_SHM "%d", id);
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_pixmap_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+ char *new_id;
+ int len;
+
+ /*!
+ * \NOTE
+ * Before call the buffer_handler_pixmap_ref function,
+ * You should make sure that the is_loaded value is toggled (1)
+ * Or the buffer_handler_pixmap_ref function will return NULL
+ */
+ info->is_loaded = 1;
+
+ if (info->buffer) {
+ DbgPrint("Buffer is already exists, but override it with new one\n");
+ }
+
+ buffer = buffer_handler_pixmap_ref(info);
+ if (!buffer) {
+ DbgPrint("Failed to make a reference of a pixmap\n");
+ info->is_loaded = 0;
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ info->is_loaded = 0;
+ buffer_handler_pixmap_unref(buffer);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ DbgFree(info->id);
+ info->id = new_id;
+
+ gem = (struct gem_data *)buffer->data;
+
+ snprintf(info->id, len, SCHEMA_PIXMAP "%d:%d", (int)gem->pixmap, info->pixel_size);
+ DbgPrint("Loaded pixmap(info->id): %s\n", info->id);
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_load(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("buffer handler is nil\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (info->is_loaded) {
+ DbgPrint("Buffer is already loaded\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ ret = load_file_buffer(info);
+ (void)create_lock_file(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ ret = load_shm_buffer(info);
+ (void)create_lock_file(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = load_pixmap_buffer(info);
+ break;
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+static inline int unload_file_buffer(struct buffer_info *info)
+{
+ const char *path;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ DbgFree(info->buffer);
+ info->buffer = NULL;
+
+ path = util_uri_to_path(info->id);
+ if (path && unlink(path) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int unload_shm_buffer(struct buffer_info *info)
+{
+ int id;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_SHM "-1");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
+ ErrPrint("%s Invalid ID\n", info->id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (id < 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (shmdt(info->buffer) < 0) {
+ ErrPrint("Detach shm: %s\n", strerror(errno));
+ }
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("Remove shm: %s\n", strerror(errno));
+ }
+
+ info->buffer = NULL;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int unload_pixmap_buffer(struct buffer_info *info)
+{
+ int id;
+ char *new_id;
+ int pixels;
+
+ new_id = strdup(SCHEMA_PIXMAP "0:0");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &id, &pixels) != 2) {
+ ErrPrint("Invalid ID (%s)\n", info->id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (id == 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ /*!
+ * Decrease the reference counter.
+ */
+ buffer_handler_pixmap_unref(info->buffer);
+
+ /*!
+ * \note
+ * Just clear the info->buffer.
+ * It will be reallocated again.
+ */
+ info->buffer = NULL;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_unload(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("buffer handler is NIL\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ (void)destroy_lock_file(info);
+ ret = unload_file_buffer(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ (void)destroy_lock_file(info);
+ ret = unload_shm_buffer(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = unload_pixmap_buffer(info);
+ break;
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ if (ret == 0) {
+ info->is_loaded = 0;
+ }
+
+ return ret;
+}
+
+EAPI const char *buffer_handler_id(const struct buffer_info *info)
+{
+ return info ? info->id : "";
+}
+
+EAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
+{
+ return info ? info->type : BUFFER_TYPE_ERROR;
+}
+
+EAPI void *buffer_handler_fb(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info) {
+ return NULL;
+ }
+
+ buffer = info->buffer;
+
+ if (info->type == BUFFER_TYPE_PIXMAP) {
+ void *canvas;
+ int ret;
+
+ /*!
+ * \note
+ * For getting the buffer address of gem.
+ */
+ canvas = buffer_handler_pixmap_acquire_buffer(info);
+ ret = buffer_handler_pixmap_release_buffer(canvas);
+ if (ret < 0) {
+ ErrPrint("Failed to release buffer: %d\n", ret);
+ }
+ return canvas;
+ }
+
+ return buffer->data;
+}
+
+EAPI int buffer_handler_pixmap(const struct buffer_info *info)
+{
+ struct buffer *buf;
+ struct gem_data *gem;
+
+ if (!info) {
+ ErrPrint("Inavlid buffer handler\n");
+ return 0;
+ }
+
+ if (info->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Invalid buffer type\n");
+ return 0;
+ }
+
+ buf = (struct buffer *)info->buffer;
+ if (!buf) {
+ ErrPrint("Invalid buffer data\n");
+ return 0;
+ }
+
+ gem = (struct gem_data *)buf->data;
+ return gem->pixmap;
+}
+
+EAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info || !info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return NULL;
+ }
+
+ buffer = buffer_handler_pixmap_ref(info);
+ if (!buffer) {
+ return NULL;
+ }
+
+ return acquire_gem(buffer);
+}
+
+EAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+
+ if (!info) {
+ return NULL;
+ }
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return NULL;
+ }
+
+ buffer = info->buffer;
+ if (!buffer) {
+ return NULL;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ return gem->compensate_data ? gem->compensate_data : gem->data;
+}
+
+/*!
+ * \return "buffer" object (Not the buffer_info)
+ */
+EAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return NULL;
+ }
+
+ if (info->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Buffer type is not matched\n");
+ return NULL;
+ }
+
+ buffer = info->buffer;
+ if (!buffer) {
+ int need_gem = 1;
+
+ buffer = create_pixmap(info);
+ if (!buffer) {
+ ErrPrint("Failed to create a pixmap\n");
+ return NULL;
+ }
+
+ info->buffer = buffer;
+
+ if (info->inst) {
+ struct pkg_info *pkg;
+
+ if (instance_lb_buffer(info->inst) == info) {
+ pkg = instance_package(info->inst);
+ if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ need_gem = 0;
+ }
+ } else if (instance_pd_buffer(info->inst) == info) {
+ pkg = instance_package(info->inst);
+ if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ need_gem = 0;
+ }
+ }
+ }
+
+ if (need_gem) {
+ create_gem(buffer);
+ }
+
+ } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Invalid buffer\n");
+ return NULL;
+ } else if (buffer->refcnt > 0) {
+ buffer->refcnt++;
+ return buffer;
+ }
+
+ s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
+ return buffer;
+}
+
+/*!
+ * \return "buffer"
+ */
+EAPI void *buffer_handler_pixmap_find(int pixmap)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+ Eina_List *l;
+ Eina_List *n;
+
+ if (pixmap == 0) {
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
+ if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+ DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
+ continue;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (gem->pixmap == pixmap) {
+ return buffer;
+ }
+ }
+
+ return NULL;
+}
+
+EAPI int buffer_handler_pixmap_release_buffer(void *canvas)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+ Eina_List *l;
+ Eina_List *n;
+ void *_ptr;
+
+ if (!canvas) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
+ if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+ continue;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
+
+ if (!_ptr) {
+ continue;
+ }
+
+ if (_ptr == canvas) {
+ release_gem(buffer);
+ buffer_handler_pixmap_unref(buffer);
+ return LB_STATUS_SUCCESS;
+ }
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+/*!
+ * \note
+ *
+ * \return Return NULL if the buffer is in still uses.
+ * Return buffer_ptr if it needs to destroy
+ */
+EAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
+{
+ struct buffer *buffer = buffer_ptr;
+ struct buffer_info *info;
+
+ buffer->refcnt--;
+ if (buffer->refcnt > 0) {
+ return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
+ }
+
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+
+ info = buffer->info;
+
+ if (destroy_gem(buffer) < 0) {
+ ErrPrint("Failed to destroy gem buffer\n");
+ }
+
+ if (destroy_pixmap(buffer) < 0) {
+ ErrPrint("Failed to destroy pixmap\n");
+ }
+
+ if (info && info->buffer == buffer) {
+ info->buffer = NULL;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_is_loaded(const struct buffer_info *info)
+{
+ return info ? info->is_loaded : 0;
+}
+
+EAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
+{
+ if (!info) {
+ return;
+ }
+
+ info->w = w;
+ info->h = h;
+}
+
+EAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("Invalid handler\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (info->w == w && info->h == h) {
+ DbgPrint("No changes\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ buffer_handler_update_size(info, w, h);
+
+ if (!info->is_loaded) {
+ DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
+ return LB_STATUS_SUCCESS;
+ }
+
+ ret = buffer_handler_unload(info);
+ if (ret < 0) {
+ ErrPrint("Unload: %d\n", ret);
+ }
+
+ ret = buffer_handler_load(info);
+ if (ret < 0) {
+ ErrPrint("Load: %d\n", ret);
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
+{
+ if (!info) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (w) {
+ *w = info->w;
+ }
+ if (h) {
+ *h = info->h;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
+{
+ return info->inst;
+}
+
+/*!
+ * \note
+ * Only for used S/W Backend
+ */
+static inline int sync_for_pixmap(struct buffer *buffer)
+{
+ XShmSegmentInfo si;
+ XImage *xim;
+ GC gc;
+ Display *disp;
+ struct gem_data *gem;
+ Screen *screen;
+ Visual *visual;
+
+ if (buffer->state != CREATED) {
+ ErrPrint("Invalid state of a FB\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (buffer->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Invalid buffer\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ ErrPrint("Failed to get a display\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (gem->w == 0 || gem->h == 0) {
+ DbgPrint("Nothing can be sync\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
+ if (si.shmid < 0) {
+ ErrPrint("shmget: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ si.readOnly = False;
+ si.shmaddr = shmat(si.shmid, NULL, 0);
+ if (si.shmaddr == (void *)-1) {
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ screen = DefaultScreenOfDisplay(disp);
+ visual = DefaultVisualOfScreen(screen);
+ /*!
+ * \NOTE
+ * XCreatePixmap can only uses 24 bits depth only.
+ */
+ xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
+ if (xim == NULL) {
+ if (shmdt(si.shmaddr) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ xim->data = si.shmaddr;
+ XShmAttach(disp, &si);
+ XSync(disp, False);
+
+ gc = XCreateGC(disp, gem->pixmap, 0, NULL);
+ if (!gc) {
+ XShmDetach(disp, &si);
+ XDestroyImage(xim);
+
+ if (shmdt(si.shmaddr) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
+
+ /*!
+ * \note Do not send the event.
+ * Instead of X event, master will send the updated event to the viewer
+ */
+ XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
+ XSync(disp, False);
+
+ XFreeGC(disp, gc);
+ XShmDetach(disp, &si);
+ XDestroyImage(xim);
+
+ if (shmdt(si.shmaddr) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI void buffer_handler_flush(struct buffer_info *info)
+{
+ int fd;
+ int size;
+ struct buffer *buffer;
+
+ if (!info || !info->buffer) {
+ return;
+ }
+
+ buffer = info->buffer;
+
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ if (s_info.fd > 0) {
+ //return;
+ //PERF_INIT();
+ //PERF_BEGIN();
+ XRectangle rect;
+ XserverRegion region;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = info->w;
+ rect.height = info->h;
+
+ region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
+ XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
+ XFixesDestroyRegion(ecore_x_display_get(), region);
+ XFlush(ecore_x_display_get());
+ //PERF_MARK("XFlush");
+ } else {
+ if (sync_for_pixmap(buffer) < 0) {
+ ErrPrint("Failed to sync via S/W Backend\n");
+ }
+ }
+ } else if (buffer->type == BUFFER_TYPE_FILE) {
+ fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
+ return;
+ }
+
+ size = info->w * info->h * info->pixel_size;
+ do_buffer_lock(info);
+ if (write(fd, info->buffer, size) != size) {
+ ErrPrint("Write is not completed: %s\n", strerror(errno));
+ }
+ do_buffer_unlock(info);
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ } else {
+ DbgPrint("Flush nothing\n");
+ }
+}
+
+HAPI int buffer_handler_init(void)
+{
+ int dri2Major, dri2Minor;
+ char *driverName, *deviceName;
+ drm_magic_t magic;
+
+ if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
+ ErrPrint("DRI2 is not supported\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
+ ErrPrint("DRI2 is not supported\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
+ ErrPrint("DRI2 is not supported\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (USE_SW_BACKEND) {
+ DbgPrint("Fallback to the S/W Backend\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ DbgFree(deviceName);
+ DbgFree(driverName);
+ return LB_STATUS_SUCCESS;
+ }
+
+ s_info.fd = open(deviceName, O_RDWR);
+ DbgFree(deviceName);
+ DbgFree(driverName);
+ if (s_info.fd < 0) {
+ ErrPrint("Failed to open a drm device: (%s)\n", strerror(errno));
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ drmGetMagic(s_info.fd, &magic);
+ DbgPrint("DRM Magic: 0x%X\n", magic);
+ if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
+ ErrPrint("Failed to do authenticate for DRI2\n");
+ if (close(s_info.fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.fd = -1;
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
+ if (!s_info.slp_bufmgr) {
+ ErrPrint("Failed to init bufmgr\n");
+ if (close(s_info.fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.fd = -1;
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int buffer_handler_fini(void)
+{
+ if (s_info.fd >= 0) {
+ if (close(s_info.fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.fd = -1;
+ }
+
+ if (s_info.slp_bufmgr) {
+ tbm_bufmgr_deinit(s_info.slp_bufmgr);
+ s_info.slp_bufmgr = NULL;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct buffer *raw_open_file(const char *filename)
+{
+ struct buffer *buffer;
+ int fd;
+ off_t off;
+ int ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ off = lseek(fd, 0L, SEEK_END);
+ if (off == (off_t)-1) {
+ ErrPrint("lseek: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
+ ErrPrint("lseek: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ buffer = calloc(1, sizeof(*buffer) + off);
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ buffer->state = CREATED;
+ buffer->type = BUFFER_TYPE_FILE;
+ buffer->refcnt = 0;
+ buffer->info = (void *)off;
+
+ ret = read(fd, buffer->data, off);
+ if (ret < 0) {
+ ErrPrint("read: %s\n", strerror(errno));
+ DbgFree(buffer);
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return buffer;
+}
+
+static inline int raw_close_file(struct buffer *buffer)
+{
+ DbgFree(buffer);
+ return 0;
+}
+
+static inline struct buffer *raw_open_shm(int shm)
+{
+ struct buffer *buffer;
+
+ buffer = (struct buffer *)shmat(shm, NULL, SHM_RDONLY);
+ if (buffer == (struct buffer *)-1) {
+ ErrPrint("shmat: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static inline int raw_close_shm(struct buffer *buffer)
+{
+ int ret;
+
+ ret = shmdt(buffer);
+ if (ret < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ return ret;
+}
+
+static inline struct buffer *raw_open_pixmap(unsigned int pixmap)
+{
+ struct buffer *buffer;
+
+ buffer = calloc(1, sizeof(*buffer) + DEFAULT_PIXELS);
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ buffer->state = CREATED;
+ buffer->type = BUFFER_TYPE_PIXMAP;
+
+ return buffer;
+}
+
+static inline int raw_close_pixmap(struct buffer *buffer)
+{
+ DbgFree(buffer);
+ return 0;
+}
+
+EAPI void *buffer_handler_raw_data(struct buffer *buffer)
+{
+ if (!buffer || buffer->state != CREATED) {
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+EAPI int buffer_handler_raw_size(struct buffer *buffer)
+{
+ if (!buffer || buffer->state != CREATED) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return (int)buffer->info;
+}
+
+EAPI struct buffer *buffer_handler_raw_open(enum buffer_type buffer_type, void *resource)
+{
+ struct buffer *handle;
+
+ switch (buffer_type) {
+ case BUFFER_TYPE_SHM:
+ handle = raw_open_shm((int)resource);
+ break;
+ case BUFFER_TYPE_FILE:
+ handle = raw_open_file(resource);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ handle = raw_open_pixmap((unsigned int)resource);
+ break;
+ default:
+ handle = NULL;
+ break;
+ }
+
+ return handle;
+}
+
+EAPI int buffer_handler_raw_close(struct buffer *buffer)
+{
+ int ret;
+
+ switch (buffer->type) {
+ case BUFFER_TYPE_SHM:
+ ret = raw_close_shm(buffer);
+ break;
+ case BUFFER_TYPE_FILE:
+ ret = raw_close_file(buffer);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = raw_close_pixmap(buffer);
+ break;
+ default:
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+EAPI int buffer_handler_lock(struct buffer_info *buffer)
+{
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (buffer->type == BUFFER_TYPE_FILE) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ return do_buffer_lock(buffer);
+}
+
+EAPI int buffer_handler_unlock(struct buffer_info *buffer)
+{
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (buffer->type == BUFFER_TYPE_FILE) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ return do_buffer_unlock(buffer);
+}
+
+/*!
+ * \note
+ * Only can be used by master.
+ * Plugin cannot access the user data
+ */
+
+HAPI int buffer_handler_set_data(struct buffer_info *buffer, void *data)
+{
+ if (!buffer) {
+ ErrPrint("Invalid handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ buffer->data = data;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *buffer_handler_data(struct buffer_info *buffer)
+{
+ if (!buffer) {
+ ErrPrint("Invalid handle\n");
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+HAPI int buffer_handler_destroy(struct buffer_info *info)
+{
+ Eina_List *l;
+ struct buffer *buffer;
+
+ if (!info) {
+ DbgPrint("Buffer is not created yet. info is NIL\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
+ if (buffer->info == info) {
+ buffer->info = NULL;
+ }
+ }
+
+ buffer_handler_unload(info);
+ DbgFree(info->id);
+ DbgFree(info);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
+{
+ struct buffer_info *info;
+
+ info = malloc(sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ switch (type) {
+ case BUFFER_TYPE_SHM:
+ if (pixel_size != DEFAULT_PIXELS) {
+ DbgPrint("SHM only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
+ pixel_size = DEFAULT_PIXELS;
+ }
+
+ info->id = strdup(SCHEMA_SHM "-1");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_FILE:
+ if (pixel_size != DEFAULT_PIXELS) {
+ DbgPrint("FILE only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
+ pixel_size = DEFAULT_PIXELS;
+ }
+
+ info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ info->id = strdup(SCHEMA_PIXMAP "0:0");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ default:
+ ErrPrint("Invalid type\n");
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->lock = NULL;
+ info->lock_fd = -1;
+ info->w = w;
+ info->h = h;
+ info->pixel_size = pixel_size;
+ info->type = type;
+ info->is_loaded = 0;
+ info->inst = inst;
+ info->buffer = NULL;
+ info->data = NULL;
+
+ return info;
+}
+
+/* End of a file */