From accb966903f1f2ff11f10aa3dfbd640e7756d4c6 Mon Sep 17 00:00:00 2001 From: Changyeon Lee Date: Tue, 27 Feb 2024 17:28:07 +0900 Subject: [PATCH] e_linux_dmabuf: add first implementation of ds_linux_dmabuf interface Change-Id: Ibcca21ebff22ee4a1791de00976ef5597801ea9f --- configure.ac | 2 +- packaging/enlightenment.spec | 1 + src/bin/Makefile.mk | 3 +- src/bin/e_comp_screen.c | 5 + src/bin/e_comp_wl_buffer.c | 5 + src/bin/e_linux_dmabuf.c | 357 ++++++++++++++++++++++++++++++++++++++++ src/bin/e_linux_dmabuf_intern.h | 15 ++ 7 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 src/bin/e_linux_dmabuf.c create mode 100644 src/bin/e_linux_dmabuf_intern.h diff --git a/configure.ac b/configure.ac index f8ef224..511472f 100755 --- a/configure.ac +++ b/configure.ac @@ -378,7 +378,7 @@ if test "x${e_cv_want_wayland_only}" != "xno" || test "x${e_cv_want_wayland_clie tizen-launch-server tizen-surface-server tizen-dpms-server eom-server presentation-time-server tizen-hwc-server linux-explicit-synchronization-unstable-v1-server wtz-foreign-server wtz-shell-server relative-pointer-unstable-v1-server pointer-constraints-unstable-v1-server - single-pixel-buffer-v1-server], + single-pixel-buffer-v1-server libdrm], [ have_wayland=yes AC_DEFINE_UNQUOTED([HAVE_WAYLAND],[1],[enable wayland support]) diff --git a/packaging/enlightenment.spec b/packaging/enlightenment.spec index 63a0222..e416394 100644 --- a/packaging/enlightenment.spec +++ b/packaging/enlightenment.spec @@ -68,6 +68,7 @@ BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(gobject-2.0) BuildRequires: pkgconfig(single-pixel-buffer-v1-server) BuildRequires: pkgconfig(capi-system-resource) +BuildRequires: pkgconfig(libdrm) Requires: libwayland-extension-server # for gtest/gmock diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index dfe25c0..c0f6190 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -245,7 +245,8 @@ src/bin/e_blur.c \ src/bin/e_devicemgr_keyboard_grab.c \ src/bin/e_subsurface_watcher.c \ src/bin/e_tbm_gbm_server.c \ -src/bin/e_comp_input.c +src/bin/e_comp_input.c \ +src/bin/e_linux_dmabuf.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 diff --git a/src/bin/e_comp_screen.c b/src/bin/e_comp_screen.c index a528350..db3029d 100644 --- a/src/bin/e_comp_screen.c +++ b/src/bin/e_comp_screen.c @@ -20,6 +20,7 @@ #include "e_dbus_conn_intern.h" #include "e_main_intern.h" #include "e_hwc_planes_intern.h" +#include "e_linux_dmabuf_intern.h" #include #include @@ -1180,6 +1181,10 @@ e_comp_screen_init() ELOGF("EX-SYNC", "Enabled the E_Explicit_Sync", NULL); e_main_ts_end("\tE_Explicit_Sync Init Done"); + e_main_ts_begin("\tE_Linux_Dmabuf Init"); + e_linux_dmabuf_init(e_comp_wl->wl.disp); + e_main_ts_end("\tE_Linux_Dmabuf Init Done"); + /* pointer */ e_input_device_pointer_xy_get(NULL, &ptr_x, &ptr_y); e_comp_wl->ptr.x = wl_fixed_from_int(ptr_x); diff --git a/src/bin/e_comp_wl_buffer.c b/src/bin/e_comp_wl_buffer.c index 1ba0c4a..b6ce1a0 100644 --- a/src/bin/e_comp_wl_buffer.c +++ b/src/bin/e_comp_wl_buffer.c @@ -1,6 +1,7 @@ #include "e_comp_wl_buffer_intern.h" #include "e_tbm_gbm_server_intern.h" +#include "e_linux_dmabuf_intern.h" #include "e_explicit_sync_intern.h" #include @@ -194,6 +195,10 @@ _e_comp_wl_buffer_tbm_type_get(E_Comp_Wl_Buffer *base, struct ds_buffer *ds_buff tbm_surface_h tsurface; tsurface = e_tbm_gbm_server_tbm_surface_get_from_buffer(ds_buffer); + + if (!tsurface) + tsurface = e_linux_dmabuf_tbm_surface_get_from_buffer(ds_buffer); + if (!tsurface) return EINA_FALSE; diff --git a/src/bin/e_linux_dmabuf.c b/src/bin/e_linux_dmabuf.c new file mode 100644 index 0000000..8e36d0f --- /dev/null +++ b/src/bin/e_linux_dmabuf.c @@ -0,0 +1,357 @@ +#include "e_linux_dmabuf_intern.h" +#include "e_comp_screen_intern.h" +#include "e_comp_intern.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef EGL_EXT_image_dma_buf_import_modifiers +#define EGL_EXT_image_dma_buf_import_modifiers 1 +#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 +#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 +#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 +#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 +#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 +#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 +#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 +#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 +#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 +#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 +#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufFormatsEXT (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufModifiersEXT (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); +#endif +#endif /* EGL_EXT_image_dma_buf_import_modifiers */ + +typedef struct _E_Linux_Dmabuf E_Linux_Dmabuf; +typedef struct _E_Linux_Dmabuf_Buffer E_Linux_Dmabuf_Buffer; + +static E_Linux_Dmabuf *_dmabuf = NULL; + +struct _E_Linux_Dmabuf +{ + struct ds_linux_dmabuf_v1 *ds_dmabuf; + + struct { + struct wl_listener display_destroy; + } listener; + + EGLDisplay egl_display; + PFNEGLQUERYDMABUFFORMATSEXTPROC query_dmabuf_formats; + + struct ds_linux_dmabuf_v1_format *supported_formats; + int num_formats; +}; + +struct _E_Linux_Dmabuf_Buffer +{ + struct ds_buffer *ds_buffer; + struct ds_addon ds_buffer_addon; + + tbm_surface_h tsurface; +}; + +static void +_e_linux_dmabuf_cb_display_destroy(struct wl_listener *listener, void *data) +{ + E_Linux_Dmabuf *dmabuf; + + dmabuf = wl_container_of(listener, dmabuf, listener.display_destroy); + wl_list_remove(&dmabuf->listener.display_destroy.link); + free(dmabuf->supported_formats); + free(dmabuf); +} + +static Eina_Bool +_e_linux_dmabuf_extension_check(const char *extensions, const char *extension) +{ + size_t extlen = strlen(extension); + const char *end = extensions + strlen(extensions); + + while (extensions < end) + { + size_t n = 0; + + /* Skip whitespaces, if any */ + if (*extensions == ' ') + { + extensions++; + continue; + } + + n = strcspn(extensions, " "); + + /* Compare strings */ + if (n == extlen && strncmp(extension, extensions, n) == 0) + return EINA_TRUE; + + extensions += n; + } + + return EINA_FALSE; +} + +static int * +_e_linux_dmabuf_egl_format_get(E_Linux_Dmabuf *dmabuf, size_t *num_formats) +{ + int *formats; + int num = 0; + + if (!dmabuf->query_dmabuf_formats(dmabuf->egl_display, 0, NULL, &num)) + { + ERR("fail to eglQueryDmaBufFormatsEXT"); + return NULL; + } + + formats = E_NEW(int, num); + EINA_SAFETY_ON_NULL_RETURN_VAL(formats, NULL); + + if (!dmabuf->query_dmabuf_formats(dmabuf->egl_display, num, formats, &num)) + { + ERR("fail to eglQueryDmaBufFormatsEXT"); + free(formats); + return NULL; + } + + *num_formats = num; + + return formats; +} + +static Eina_Bool +_e_linux_dmabuf_egl_format_init(E_Linux_Dmabuf *dmabuf) +{ + const char *extensions = NULL; + + if (!e_comp_gl_get()) return EINA_FALSE; + + dmabuf->egl_display = eglGetCurrentDisplay(); + if (!dmabuf->egl_display) return EINA_FALSE; + + extensions = (const char *)eglQueryString(dmabuf->egl_display, EGL_EXTENSIONS); + if (!extensions) return EINA_FALSE; + + if (!_e_linux_dmabuf_extension_check(extensions, "EGL_EXT_image_dma_buf_import_modifiers")) + return EINA_FALSE; + + dmabuf->query_dmabuf_formats = (void *)eglGetProcAddress("eglQueryDmaBufFormatsEXT"); + if (!dmabuf->query_dmabuf_formats) return EINA_FALSE; + + return EINA_TRUE; +} + +static struct ds_linux_dmabuf_v1_format * +_e_linux_dmabuf_supported_format_get(E_Linux_Dmabuf *dmabuf, int *num_formats) +{ + struct ds_linux_dmabuf_v1_format *formats; + static int fallback_formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; + static uint64_t fallback_modifier = DRM_FORMAT_MOD_LINEAR; + int *egl_formats; + size_t num = 0; + int i; + + if (!_e_linux_dmabuf_egl_format_init(dmabuf)) + goto fallback_formats; + + egl_formats = _e_linux_dmabuf_egl_format_get(dmabuf, &num); + if (!egl_formats) goto fallback_formats; + + formats = calloc(num, sizeof *formats); + EINA_SAFETY_ON_NULL_RETURN_VAL(formats, NULL); + + for (i = 0; i < num; i++) + { + formats[i].format = egl_formats[i]; + /* Currently, modifier is not supported */ + formats[i].modifiers = &fallback_modifier; + formats[i].num_modifiers = 1; + } + + *num_formats = num; + + return formats; + +fallback_formats: + num = sizeof(fallback_formats) / sizeof(fallback_formats[0]); + + formats = calloc(num, sizeof *formats); + EINA_SAFETY_ON_NULL_RETURN_VAL(formats, NULL); + + for (i = 0; i < num; i++) + { + formats[i].format = fallback_formats[0]; + formats[i].modifiers = &fallback_modifier; + formats[i].num_modifiers = 1; + } + + *num_formats = num; + + return formats; +} + +EINTERN Eina_Bool +e_linux_dmabuf_init(struct wl_display *display) +{ + E_Linux_Dmabuf *dmabuf; + + if (_dmabuf) return EINA_TRUE; + + dmabuf = E_NEW(E_Linux_Dmabuf, 1); + if (!dmabuf) + return EINA_FALSE; + + dmabuf->supported_formats = _e_linux_dmabuf_supported_format_get(dmabuf, + &dmabuf->num_formats); + if (!dmabuf->supported_formats) + { + ERR("fail to _e_linux_dmabuf_supported_format_get"); + return EINA_FALSE; + } + + dmabuf->ds_dmabuf = ds_linux_dmabuf_v1_create(display, + dmabuf->supported_formats, dmabuf->num_formats); + if (!dmabuf->ds_dmabuf) + { + ERR("Could not create ds_linux_dmabuf_v1"); + free(dmabuf); + return EINA_FALSE; + } + + dmabuf->listener.display_destroy.notify = _e_linux_dmabuf_cb_display_destroy; + wl_display_add_destroy_listener(display, &dmabuf->listener.display_destroy); + + _dmabuf = dmabuf; + + return EINA_TRUE; +} + +static void +_e_linux_dmabuf_buffer_cb_ds_buffer_destroy(struct ds_addon *addon) +{ + E_Linux_Dmabuf_Buffer *dmabuf_buffer; + + dmabuf_buffer = wl_container_of(addon, dmabuf_buffer, ds_buffer_addon); + + ds_addon_finish(&dmabuf_buffer->ds_buffer_addon); + + tbm_surface_internal_unref(dmabuf_buffer->tsurface); + free(dmabuf_buffer); +} + +static struct ds_addon_interface _e_linux_dmabuf_buffer_addon_impl = { + .name = "e_linux_dmabuf_buffer", + .destroy = _e_linux_dmabuf_buffer_cb_ds_buffer_destroy, +}; + +static E_Linux_Dmabuf_Buffer * +_e_linux_dmabuf_buffer_get_from_ds_buffer(struct ds_buffer *ds_buffer) +{ + struct ds_addon *addon; + E_Linux_Dmabuf_Buffer *dmabuf_buffer; + + addon = ds_addon_find(&ds_buffer->addons, _dmabuf, + &_e_linux_dmabuf_buffer_addon_impl); + if (!addon) return NULL; + + dmabuf_buffer = wl_container_of(addon, dmabuf_buffer, ds_buffer_addon); + + return dmabuf_buffer; +} + +EINTERN tbm_surface_h +e_linux_dmabuf_tbm_surface_get_from_buffer(struct ds_buffer *ds_buffer) +{ + E_Linux_Dmabuf_Buffer *dmabuf_buffer; + struct ds_linux_dmabuf_v1_buffer *ds_dmabuf_buffer; + const struct ds_linux_dmabuf_v1_attributes *ds_attributes; + tbm_surface_h tsurface = NULL; + tbm_surface_info_s info = {0, }; + tbm_bo bos[LINUX_DMABUF_MAX_PLANES] = {0, }; + off_t bos_size[LINUX_DMABUF_MAX_PLANES] = {0, }; + int i = 0; + + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen->bufmgr, NULL); + + if (!_dmabuf) return NULL; + + ds_dmabuf_buffer = ds_linux_dmabuf_v1_buffer_from_buffer(ds_buffer); + if (!ds_dmabuf_buffer) + return NULL; + + dmabuf_buffer = _e_linux_dmabuf_buffer_get_from_ds_buffer(ds_buffer); + if (dmabuf_buffer) + return dmabuf_buffer->tsurface; + + ds_attributes = ds_linux_dmabuf_v1_buffer_get_attributes(ds_dmabuf_buffer); + EINA_SAFETY_ON_NULL_RETURN_VAL(ds_attributes, NULL); + + info.width = ds_attributes->width; + info.height = ds_attributes->height; + info.format = ds_attributes->format; + info.num_planes = ds_attributes->num_planes; + + for (i = 0; i < info.num_planes; i++) + { + info.planes[i].stride = ds_attributes->stride[i]; + info.planes[i].offset = ds_attributes->offset[i]; + + bos[i] = tbm_bo_import_fd(e_comp->e_comp_screen->bufmgr, ds_attributes->fd[i]); + EINA_SAFETY_ON_NULL_GOTO(bos[i], failed); + + bos_size[i] = lseek(ds_attributes->fd[i], 0, SEEK_END); + EINA_SAFETY_ON_TRUE_GOTO(bos_size[i] == -1, failed); + } + + for (i = 0; i < info.num_planes; i++) + { + if ((i + 1 == info.num_planes) || (bos[i] != bos[i + 1])) + info.planes[i].size = bos_size[i] - info.planes[i].offset; + else + info.planes[i].size = info.planes[i + 1].offset - info.planes[i].offset; + + info.size += info.planes[i].size; + } + + tsurface = tbm_surface_internal_create_with_bos(&info, bos, info.num_planes); + EINA_SAFETY_ON_NULL_GOTO(tsurface, failed); + + for (i = 0; i < info.num_planes; i++) + { + if (bos[i]) + tbm_bo_unref(bos[i]); + } + + dmabuf_buffer = E_NEW(E_Linux_Dmabuf_Buffer, 1); + EINA_SAFETY_ON_NULL_GOTO(dmabuf_buffer, failed); + + dmabuf_buffer->tsurface = tsurface; + + ds_addon_init(&dmabuf_buffer->ds_buffer_addon, &ds_buffer->addons, + _dmabuf, &_e_linux_dmabuf_buffer_addon_impl); + dmabuf_buffer->ds_buffer = ds_buffer; + + return tsurface; + +failed: + for (i = 0; i < info.num_planes; i++) + { + if (bos[i]) + tbm_bo_unref(bos[i]); + } + + if (tsurface) + tbm_surface_destroy(tsurface); + + return NULL; +} diff --git a/src/bin/e_linux_dmabuf_intern.h b/src/bin/e_linux_dmabuf_intern.h new file mode 100644 index 0000000..96398cd --- /dev/null +++ b/src/bin/e_linux_dmabuf_intern.h @@ -0,0 +1,15 @@ +#ifndef E_LINUX_DMABUF_INTERN_H +#define E_LINUX_DMABUF_INTERN_H + +#include "e_intern.h" + +#include +#include + +EINTERN Eina_Bool +e_linux_dmabuf_init(struct wl_display *display); + +EINTERN tbm_surface_h +e_linux_dmabuf_tbm_surface_get_from_buffer(struct ds_buffer *ds_buffer); + +#endif /* end of include guard: E_LINUX_DMABUF_INTERN_H */ -- 2.7.4