Introduce E_Tbm_Gbm_Server 61/301261/1
authorSeunghun Lee <shiin.lee@samsung.com>
Mon, 16 Oct 2023 08:37:04 +0000 (17:37 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Mon, 13 Nov 2023 06:02:47 +0000 (15:02 +0900)
E_Tbm_Gbm_Server is to support both wayland clients using tbm surfaces
and the ones using gbm buffer objects as a wl_buffer.

This creates `ds_tbm_server` to support wl_buffer of tbm_surface and
implements `ds_buffer_interface` to support gbm buffer objects.

Change-Id: I3eea2a8d3b2e6730d37896bbe73dc382321e5c09

src/bin/Makefile.mk
src/bin/e_comp_wl_tbm.c
src/bin/e_tbm_gbm_server.c [new file with mode: 0644]
src/bin/e_tbm_gbm_server.h [new file with mode: 0644]

index f9566d3..c31b4f5 100644 (file)
@@ -284,7 +284,8 @@ src/bin/e_comp_wl_buffer.c \
 src/bin/e_compositor.c \
 src/bin/e_blender.c \
 src/bin/e_devicemgr_keyboard_grab.c \
-src/bin/e_subsurface_watcher.c
+src/bin/e_subsurface_watcher.c \
+src/bin/e_tbm_gbm_server.c
 
 src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DEFL_BETA_API_SUPPORT -DEFL_EO_API_SUPPORT -DE_LOGGING=2 @WAYLAND_CFLAGS@ $(TTRACE_CFLAGS) $(DLOG_CFLAGS) $(PIXMAN_CFLAGS) $(POLICY_CFLAGS) $(EGL_CFLAGS)
 if HAVE_LIBGOMP
index 08546af..39ab6e9 100644 (file)
@@ -1,10 +1,9 @@
 #include "e.h"
+#include "e_tbm_gbm_server.h"
 #include <wayland-tbm-server.h>
 #include <tbm_bufmgr.h>
 #include <tbm_surface_internal.h>
 #include <gbm.h>
-#include <libds-tizen/types/tbm_server.h>
-#include <libds-tizen/tbm_server.h>
 
 static uint64_t e_comp_wl_tbm_gbm_bo_key;
 #define E_COMP_WL_TBM_GBM_BO_KEY  (unsigned long)(&e_comp_wl_tbm_gbm_bo_key)
@@ -155,18 +154,9 @@ e_comp_wl_tbm_egl_image_buffer_get(int width, int height, tbm_format format)
    return NULL;
 }
 
-static void
-_e_comp_wl_tbm_cb_display_destroy(struct wl_listener *listener, void *data)
-{
-   e_comp->wl_comp_data->tbm.server = NULL;
-}
-
 EINTERN Eina_Bool
 e_comp_wl_tbm_init(void)
 {
-   static struct wl_listener display_destroy;
-   struct ds_tbm_server *ds_tbm_server;
-
    if (!e_comp)
      {
         e_error_message_show(_("Enlightenment cannot has no e_comp at Wayland TBM!\n"));
@@ -178,17 +168,12 @@ e_comp_wl_tbm_init(void)
    if (e_comp->wl_comp_data->tbm.server)
       return EINA_TRUE;
 
-   ds_tbm_server = ds_tbm_server_create(e_comp->wl_comp_data->wl.disp);
-   if (!ds_tbm_server)
+   if (!e_tbm_gbm_server_init(e_comp->wl_comp_data->wl.disp))
      {
-        e_error_message_show(_("Enlightenment cannot initialize ds_tbm_server!\n"));
+        e_error_message_show(_("Enlightenment cannot initialize E_Tbm_Gbm_Server!!\n"));
         return EINA_FALSE;
      }
 
-   e_comp->wl_comp_data->tbm.server = (void *)ds_tbm_server->wl_tbm;
-   display_destroy.notify = _e_comp_wl_tbm_cb_display_destroy;
-   ds_tbm_server_add_destroy_listener(ds_tbm_server, &display_destroy);
-
    if (e_comp_socket_init("tbm-drm-auth"))
      PRCTL("[Winsys] change permission and create sym link for %s", "tbm-drm-auth");
 
diff --git a/src/bin/e_tbm_gbm_server.c b/src/bin/e_tbm_gbm_server.c
new file mode 100644 (file)
index 0000000..4ae6518
--- /dev/null
@@ -0,0 +1,346 @@
+#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,
+};
diff --git a/src/bin/e_tbm_gbm_server.h b/src/bin/e_tbm_gbm_server.h
new file mode 100644 (file)
index 0000000..27b5cdb
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef E_TBM_GBM_SERVER_H
+#define E_TBM_GBM_SERVER_H
+
+#include <Eina.h>
+#include <wayland-server.h>
+#include <libds/buffer.h>
+#include <tbm_surface.h>
+
+typedef struct _E_Gbm_Client_Buffer E_Gbm_Client_Buffer;
+
+Eina_Bool e_tbm_gbm_server_init(struct wl_display *display);
+tbm_surface_h e_tbm_gbm_server_tbm_surface_get_from_buffer(struct ds_buffer *ds_buffer);
+
+#endif /* end of include guard: E_TBM_GBM_SERVER_H */