--- /dev/null
+#include "e.h"
+#include <assert.h>
+#include <stdbool.h>
+#include <gbm.h>
+#include <libds/interfaces/buffer.h>
+#include <libds-tizen/types/tbm_server.h>
+#include <libds-tizen/tbm_server.h>
+#include <libds-tizen/pixel_format.h>
+
+#include "e_tbm_gbm_server.h"
+
+typedef struct _E_Tbm_Gbm_Server E_Tbm_Gbm_Server;
+typedef struct _E_Gbm_Client_Buffer E_Gbm_Client_Buffer;
+
+struct _E_Tbm_Gbm_Server
+{
+ struct ds_tbm_server *tbm_server;
+ struct wl_listener tbm_server_destroy;
+ struct wl_listener display_destroy;
+};
+
+struct _E_Gbm_Client_Buffer
+{
+ struct ds_buffer base;
+
+ tbm_surface_h tbm_surface;
+ struct wl_resource *resource;
+
+ struct wl_listener release;
+ struct wl_listener resource_destroy;
+
+ uint32_t format;
+};
+
+static const struct ds_buffer_resource_interface _e_gbm_client_buffer_resource_iface;
+static const struct ds_buffer_interface _e_gbm_client_buffer_iface;
+
+static void _e_tbm_gbm_server_cb_tbm_server_destroy(struct wl_listener *listener, void *data);
+static void _e_tbm_gbm_server_cb_display_destroy(struct wl_listener *listener, void *data);
+static void _e_comp_tbm_server_set(struct wayland_tbm_server *wl_tbm_server);
+static E_Gbm_Client_Buffer *_e_gbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer);
+
+EINTERN Eina_Bool
+e_tbm_gbm_server_init(struct wl_display *display)
+{
+ E_Tbm_Gbm_Server *server;
+
+ server = E_NEW(E_Tbm_Gbm_Server, 1);
+ if (!server)
+ return EINA_FALSE;
+
+ server->tbm_server = ds_tbm_server_create(display);
+ if (!server->tbm_server)
+ {
+ ERR("Could not create ds_tbm_server");
+ free(server);
+ return EINA_FALSE;
+ }
+
+ _e_comp_tbm_server_set(server->tbm_server->wl_tbm);
+
+ server->tbm_server_destroy.notify = _e_tbm_gbm_server_cb_tbm_server_destroy;
+ ds_tbm_server_add_destroy_listener(server->tbm_server, &server->tbm_server_destroy);
+
+ server->display_destroy.notify = _e_tbm_gbm_server_cb_display_destroy;
+ wl_display_add_destroy_listener(display, &server->display_destroy);
+
+ ds_buffer_register_resource_interface(&_e_gbm_client_buffer_resource_iface);
+
+ return EINA_TRUE;
+}
+
+EINTERN tbm_surface_h
+e_tbm_gbm_server_tbm_surface_get_from_buffer(struct ds_buffer *ds_buffer)
+{
+ E_Gbm_Client_Buffer *gbm_client_buffer;
+ struct ds_tbm_client_buffer *tbm_client_buffer;
+
+ tbm_client_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
+ if (tbm_client_buffer)
+ return ds_tbm_client_buffer_get_tbm_surface(tbm_client_buffer);
+
+ if (ds_buffer->iface == &_e_gbm_client_buffer_iface)
+ {
+ gbm_client_buffer = _e_gbm_client_buffer_from_buffer(ds_buffer);
+ return gbm_client_buffer->tbm_surface;
+ }
+
+ return NULL;
+}
+
+static void
+_e_comp_tbm_server_set(struct wayland_tbm_server *wl_tbm_server)
+{
+ e_comp->wl_comp_data->tbm.server = (void *)wl_tbm_server;
+}
+
+static void
+_e_tbm_server_unset(E_Tbm_Gbm_Server *server)
+{
+ if (!server->tbm_server)
+ return;
+
+ wl_list_remove(&server->tbm_server_destroy.link);
+ server->tbm_server = NULL;
+
+ _e_comp_tbm_server_set(NULL);
+}
+
+static void
+_e_tbm_gbm_server_cb_tbm_server_destroy(struct wl_listener *listener, void *data)
+{
+ E_Tbm_Gbm_Server *server;
+
+ server = wl_container_of(listener, server, tbm_server_destroy);
+ _e_tbm_server_unset(server);
+}
+
+static void
+_e_tbm_gbm_server_cb_display_destroy(struct wl_listener *listener, void *data)
+{
+ E_Tbm_Gbm_Server *server;
+
+ server = wl_container_of(listener, server, display_destroy);
+ _e_tbm_server_unset(server);
+ wl_list_remove(&server->display_destroy.link);
+ free(server);
+}
+
+static E_Gbm_Client_Buffer *
+_e_gbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ assert(ds_buffer->iface == &_e_gbm_client_buffer_iface);
+ return wl_container_of(ds_buffer, buffer, base);
+}
+
+static void
+_e_gbm_client_buffer_iface_destroy(struct ds_buffer *ds_buffer)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ buffer = _e_gbm_client_buffer_from_buffer(ds_buffer);
+
+ if (buffer->resource)
+ {
+ wl_list_remove(&buffer->resource_destroy.link);
+ wl_list_remove(&buffer->release.link);
+ }
+
+ tbm_surface_internal_unref(buffer->tbm_surface);
+ free(buffer);
+}
+
+static tbm_bo_access_option
+_e_gbm_client_buffer_tbm_bo_access_option_from_ds_access_flags(enum ds_buffer_data_ptr_access_flag flags)
+{
+ tbm_bo_access_option op = TBM_OPTION_NONE;
+
+ if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ)
+ op |= TBM_OPTION_READ;
+
+ if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE)
+ op |= TBM_OPTION_WRITE;
+
+ return op;
+}
+
+static bool
+_e_gbm_client_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer, enum ds_buffer_data_ptr_access_flag flags, void **data, uint32_t *format, size_t *stride)
+{
+ E_Gbm_Client_Buffer *buffer;
+ tbm_surface_info_s info;
+ tbm_bo_access_option op;
+ int err;
+
+ buffer = _e_gbm_client_buffer_from_buffer(ds_buffer);
+ op = _e_gbm_client_buffer_tbm_bo_access_option_from_ds_access_flags(flags);
+ err = tbm_surface_map(buffer->tbm_surface, op, &info);
+ if (err != TBM_SURFACE_ERROR_NONE)
+ {
+ ERR("Failed tbm_surface_map()");
+ return false;
+ }
+
+ *format = ds_tizen_pixel_format_convert_tbm_to_drm(info.format);
+ *stride = info.planes[0].stride;
+ *data = info.planes[0].ptr;
+
+ return false;
+}
+
+static void
+_e_gbm_client_buffer_iface_end_data_ptr_access(struct ds_buffer *ds_buffer)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ buffer = _e_gbm_client_buffer_from_buffer(ds_buffer);
+ tbm_surface_unmap(buffer->tbm_surface);
+}
+
+static struct wl_resource *
+_e_gbm_client_buffer_iface_get_resource(struct ds_buffer *ds_buffer)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ buffer = _e_gbm_client_buffer_from_buffer(ds_buffer);
+ return buffer->resource;
+}
+
+static const struct ds_buffer_interface _e_gbm_client_buffer_iface =
+{
+ .destroy = _e_gbm_client_buffer_iface_destroy,
+ .begin_data_ptr_access = _e_gbm_client_buffer_iface_begin_data_ptr_access,
+ .end_data_ptr_access = _e_gbm_client_buffer_iface_end_data_ptr_access,
+ .get_resource = _e_gbm_client_buffer_iface_get_resource,
+};
+
+static void
+_e_gbm_client_buffer_cb_resource_destroy(struct wl_listener *listener, void *data)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ buffer = wl_container_of(listener, buffer, resource_destroy);
+ buffer->resource = NULL;
+ wl_list_remove(&buffer->release.link);
+ wl_list_remove(&buffer->resource_destroy.link);
+ ds_buffer_drop(&buffer->base);
+}
+
+static void
+_e_gbm_client_buffer_cb_release(struct wl_listener *listener, void *data)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ buffer = wl_container_of(listener, buffer, release);
+ wl_buffer_send_release(buffer->resource);
+}
+
+static tbm_surface_h
+_e_gbm_client_buffer_tbm_surface_create_with_gbm_bo(struct gbm_bo *gbm_bo)
+{
+ tbm_surface_h tbm_surface;
+
+ tbm_surface = e_comp_wl_tbm_import_gbm_bo(gbm_bo);
+ if (!tbm_surface)
+ return NULL;
+
+ if (!e_comp_wl_tbm_gbm_bo_user_data_set(tbm_surface, gbm_bo))
+ {
+ tbm_surface_destroy(tbm_surface);
+ return NULL;
+ }
+
+ return tbm_surface;
+}
+
+static E_Gbm_Client_Buffer *
+_e_gbm_client_buffer_create(struct wl_resource *resource)
+{
+ void *gbm_device = e_comp->e_comp_screen->gdevice;
+ struct gbm_bo *gbm_bo;
+ E_Gbm_Client_Buffer *buffer;
+
+ if (!gbm_device)
+ return NULL;
+
+ gbm_bo = gbm_bo_import(gbm_device, GBM_BO_IMPORT_WL_BUFFER, resource, GBM_BO_USE_RENDERING);
+ if (!gbm_bo)
+ return NULL;
+
+ buffer = E_NEW(E_Gbm_Client_Buffer, 1);
+ if (!buffer)
+ goto err_alloc;
+
+ buffer->tbm_surface = _e_gbm_client_buffer_tbm_surface_create_with_gbm_bo(gbm_bo);
+ if (!buffer->tbm_surface)
+ goto err_tbm_surface;
+
+ ds_buffer_init(&buffer->base,
+ &_e_gbm_client_buffer_iface,
+ tbm_surface_get_width(buffer->tbm_surface),
+ tbm_surface_get_height(buffer->tbm_surface));
+
+ buffer->resource = resource;
+
+ buffer->resource_destroy.notify = _e_gbm_client_buffer_cb_resource_destroy;
+ wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
+
+ buffer->release.notify = _e_gbm_client_buffer_cb_release;
+ ds_buffer_add_release_listener(&buffer->base, &buffer->release);
+
+ return buffer;
+
+err_tbm_surface:
+ free(buffer);
+err_alloc:
+ gbm_bo_destroy(gbm_bo);
+
+ return NULL;
+}
+
+static E_Gbm_Client_Buffer *
+_e_gbm_client_buffer_get_or_create(struct wl_resource *resource)
+{
+ E_Gbm_Client_Buffer *buffer;
+ struct wl_listener *listener;
+
+ listener = wl_resource_get_destroy_listener(resource, _e_gbm_client_buffer_cb_resource_destroy);
+ if (listener)
+ {
+ buffer = wl_container_of(listener, buffer, resource_destroy);
+ return buffer;
+ }
+
+ return _e_gbm_client_buffer_create(resource);
+}
+
+static bool
+_e_gbm_client_buffer_resource_iface_is_instance(struct wl_resource *resource)
+{
+ if (_e_gbm_client_buffer_get_or_create(resource))
+ return true;
+
+ return false;
+}
+
+static struct ds_buffer *
+_e_gbm_client_buffer_resource_iface_from_resource(struct wl_resource *resource)
+{
+ E_Gbm_Client_Buffer *buffer;
+
+ buffer = _e_gbm_client_buffer_get_or_create(resource);
+ if (!buffer)
+ return NULL;
+
+ return &buffer->base;
+}
+
+static const struct ds_buffer_resource_interface _e_gbm_client_buffer_resource_iface =
+{
+ .name = "E_Gbm",
+ .is_instance = _e_gbm_client_buffer_resource_iface_is_instance,
+ .from_resource = _e_gbm_client_buffer_resource_iface_from_resource,
+};