diff options
author | Derek Foreman <derekf@osg.samsung.com> | 2017-11-13 16:26:09 -0600 |
---|---|---|
committer | Derek Foreman <derekf@osg.samsung.com> | 2017-11-15 11:54:37 -0600 |
commit | 9fdcf7d0eb8cec792a84ac0f0aac9c2ea5389293 (patch) | |
tree | 9d0618096907252687ef54524afe8ac14d87728d | |
parent | f6ec5b961b4cec2b5784b4ecbd8f33159b786cbc (diff) | |
download | efl-9fdcf7d0eb8cec792a84ac0f0aac9c2ea5389293.tar.gz |
wayland_shm/ecore_wl2: Move buffer allocation into ecore_wl2
This moves all the platform specific buffer allocation into ecore_wl2
instead of the engine.
Note that this makes an internal struct available in the header. This
will be removed shortly.
-rw-r--r-- | src/Makefile_Ecore_Wl2.am | 14 | ||||
-rw-r--r-- | src/Makefile_Evas.am | 14 | ||||
-rw-r--r-- | src/lib/ecore_wl2/Ecore_Wl2.h | 40 | ||||
-rw-r--r-- | src/lib/ecore_wl2/ecore_wl2_buffer.c | 559 | ||||
-rw-r--r-- | src/modules/evas/engines/wayland_shm/evas_dmabuf.c | 569 | ||||
-rw-r--r-- | src/modules/evas/engines/wayland_shm/evas_engine.h | 8 |
6 files changed, 613 insertions, 591 deletions
diff --git a/src/Makefile_Ecore_Wl2.am b/src/Makefile_Ecore_Wl2.am index c2baa29a15..3abab865af 100644 --- a/src/Makefile_Ecore_Wl2.am +++ b/src/Makefile_Ecore_Wl2.am @@ -15,7 +15,17 @@ lib/ecore_wl2/ecore_wl2_input.c \ lib/ecore_wl2/ecore_wl2_output.c \ lib/ecore_wl2/ecore_wl2_display.c \ lib/ecore_wl2/ecore_wl2.c \ -lib/ecore_wl2/ecore_wl2_private.h +lib/ecore_wl2/ecore_wl2_private.h \ +lib/ecore_wl2/ecore_wl2_buffer.c \ +static_libs/libdrm/drm_fourcc.h \ +static_libs/libdrm/drm.h \ +static_libs/libdrm/drm_mode.h \ +static_libs/libdrm/exynos_drm.h \ +static_libs/libdrm/exynos_drmif.h \ +static_libs/libdrm/i915_drm.h \ +static_libs/libdrm/intel_bufmgr.h \ +static_libs/libdrm/LICENSE + nodist_lib_ecore_wl2_libecore_wl2_la_SOURCES = \ lib/ecore_wl2/efl-aux-hints-protocol.c \ @@ -35,7 +45,7 @@ lib/ecore_wl2/text-input-unstable-v1-protocol.c \ lib/ecore_wl2/efl-hints-client-protocol.h \ lib/ecore_wl2/efl-hints-protocol.c -lib_ecore_wl2_libecore_wl2_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_WL2_CFLAGS@ +lib_ecore_wl2_libecore_wl2_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_WL2_CFLAGS@ -I$(top_srcdir)/src/static_libs/libdrm lib_ecore_wl2_libecore_wl2_la_LIBADD = @ECORE_WL2_LIBS@ lib_ecore_wl2_libecore_wl2_la_DEPENDENCIES = @ECORE_WL2_INTERNAL_LIBS@ lib_ecore_wl2_libecore_wl2_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 408c0c7583..48e6440e78 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -1321,15 +1321,7 @@ modules/evas/engines/wayland_common/Evas_Engine_Wayland.h \ modules/evas/engines/wayland_shm/evas_engine.c \ modules/evas/engines/wayland_shm/evas_engine.h \ modules/evas/engines/wayland_shm/evas_dmabuf.c \ -modules/evas/engines/wayland_shm/evas_outbuf.c \ -static_libs/libdrm/drm_fourcc.h \ -static_libs/libdrm/drm.h \ -static_libs/libdrm/drm_mode.h \ -static_libs/libdrm/exynos_drm.h \ -static_libs/libdrm/exynos_drmif.h \ -static_libs/libdrm/i915_drm.h \ -static_libs/libdrm/intel_bufmgr.h \ -static_libs/libdrm/LICENSE +modules/evas/engines/wayland_shm/evas_outbuf.c NODIST_WAYLAND_SHM_SOURCES = \ lib/ecore_wl2/linux-dmabuf-unstable-v1-protocol.c @@ -1337,8 +1329,7 @@ lib/ecore_wl2/linux-dmabuf-unstable-v1-protocol.c if EVAS_STATIC_BUILD_WAYLAND_SHM nodist_lib_evas_libevas_la_SOURCES = $(NODIST_WAYLAND_SHM_SOURCES) lib_evas_libevas_la_SOURCES += $(WAYLAND_SHM_SOURCES) -lib_evas_libevas_la_CPPFLAGS += @evas_engine_wayland_shm_cflags@ \ --I$(top_srcdir)/src/static_libs/libdrm +lib_evas_libevas_la_CPPFLAGS += @evas_engine_wayland_shm_cflags@ lib_evas_libevas_la_LIBADD += @evas_engine_wayland_shm_libs@ else enginewaylandshmpkgdir = $(libdir)/evas/modules/engines/wayland_shm/$(MODULE_ARCH) @@ -1356,7 +1347,6 @@ modules_evas_engines_wayland_shm_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/ -I$(top_srcdir)/src/lib/evas/cserve2 \ -I$(top_srcdir)/src/lib/ecore_wl2 \ -I$(top_builddir)/src/lib/ecore_wl2 \ --I$(top_srcdir)/src/static_libs/libdrm \ -I$(top_srcdir)/src/modules/evas/engines/wayland_common \ @EVAS_CFLAGS@ \ @ECORE_WL2_CFLAGS@ \ diff --git a/src/lib/ecore_wl2/Ecore_Wl2.h b/src/lib/ecore_wl2/Ecore_Wl2.h index a9a3da232d..f4c1c8122a 100644 --- a/src/lib/ecore_wl2/Ecore_Wl2.h +++ b/src/lib/ecore_wl2/Ecore_Wl2.h @@ -359,6 +359,36 @@ typedef struct Ecore_Wl2_Event_Aux_Message Ecore_Wl2_Display *display; } Ecore_Wl2_Event_Aux_Message; +/* THIS WILL BE PRIVATE SHORTLY, DO NOT USE */ +typedef struct _Buffer_Handle Buffer_Handle; +typedef struct _Ecore_Wl2_Buffer Ecore_Wl2_Buffer; +struct _Ecore_Wl2_Buffer +{ + struct wl_buffer *wl_buffer; + int size; + int w, h; + int age; + unsigned long stride; + Buffer_Handle *bh; + int fd; + void *mapping; + + int index; + Eina_Bool locked : 1; + Eina_Bool busy : 1; + Eina_Bool used : 1; + Eina_Bool orphaned : 1; + Eina_Bool alpha : 1; +}; + +typedef enum _Ecore_Wl2_Buffer_Type Ecore_Wl2_Buffer_Type; +enum _Ecore_Wl2_Buffer_Type +{ + ECORE_WL2_BUFFER_NONE = 0, + ECORE_WL2_BUFFER_SHM = 1, + ECORE_WL2_BUFFER_DMABUF = 2 +}; + typedef void (*Ecore_Wl2_Bind_Cb)(struct wl_client *client, void *data, uint32_t version, uint32_t id); typedef void (*Ecore_Wl2_Unbind_Cb)(struct wl_resource *resource); typedef void (*Ecore_Wl2_Frame_Cb)(Ecore_Wl2_Window *win, uint32_t timestamp, void *data); @@ -1976,6 +2006,16 @@ EAPI void ecore_wl2_window_update_begin(Ecore_Wl2_Window *window); EAPI void ecore_wl2_window_damage(Ecore_Wl2_Window *window, Eina_Rectangle *rects, unsigned int count); +EAPI Eina_Bool ecore_wl2_buffer_init(Ecore_Wl2_Buffer_Type types); +EAPI Ecore_Wl2_Buffer *ecore_wl2_buffer_create(Ecore_Wl2_Display *ewd, int w, int h, Eina_Bool alpha); +EAPI void ecore_wl2_buffer_destroy(Ecore_Wl2_Buffer *b); +EAPI struct wl_buffer *ecore_wl2_buffer_wl_buffer_get(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *buf); +EAPI void *ecore_wl2_buffer_map(Ecore_Wl2_Buffer *buf); +EAPI void ecore_wl2_buffer_unmap(Ecore_Wl2_Buffer *buf); +EAPI void ecore_wl2_buffer_discard(Ecore_Wl2_Buffer *buf); +EAPI void ecore_wl2_buffer_unlock(Ecore_Wl2_Buffer *b); +EAPI void ecore_wl2_buffer_destroy(Ecore_Wl2_Buffer *b); + # endif # undef EAPI diff --git a/src/lib/ecore_wl2/ecore_wl2_buffer.c b/src/lib/ecore_wl2/ecore_wl2_buffer.c new file mode 100644 index 0000000000..32e779ed00 --- /dev/null +++ b/src/lib/ecore_wl2/ecore_wl2_buffer.c @@ -0,0 +1,559 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ecore_wl2_private.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dlfcn.h> +#include <drm_fourcc.h> +#include <intel_bufmgr.h> +#include <i915_drm.h> + +#include <exynos_drm.h> +#include <exynos_drmif.h> +#include <sys/mman.h> + +#include "linux-dmabuf-unstable-v1-client-protocol.h" + +#define SYM(lib, xx) \ + do { \ + sym_## xx = dlsym(lib, #xx); \ + if (!(sym_ ## xx)) { \ + fail = EINA_TRUE; \ + } \ + } while (0) + +static int drm_fd = -1; + +typedef struct _Dmabuf_Surface Dmabuf_Surface; + +typedef struct _Ecore_Wl2_Buffer Ecore_Wl2_Buffer; +typedef struct _Buffer_Handle Buffer_Handle; +typedef struct _Buffer_Manager Buffer_Manager; +struct _Buffer_Manager +{ + Buffer_Handle *(*alloc)(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd); + struct wl_buffer *(*to_buffer)(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db); + void *(*map)(Ecore_Wl2_Buffer *buf); + void (*unmap)(Ecore_Wl2_Buffer *buf); + void (*discard)(Ecore_Wl2_Buffer *buf); + void (*manager_destroy)(void); + void *priv; + void *dl_handle; + int refcount; + Eina_Bool destroyed; +}; + +static Buffer_Manager *buffer_manager = NULL; + +static drm_intel_bufmgr *(*sym_drm_intel_bufmgr_gem_init)(int fd, int batch_size) = NULL; +static int (*sym_drm_intel_bo_unmap)(drm_intel_bo *bo) = NULL; +static int (*sym_drm_intel_bo_map)(drm_intel_bo *bo) = NULL; +static drm_intel_bo *(*sym_drm_intel_bo_alloc_tiled)(drm_intel_bufmgr *mgr, const char *name, int x, int y, int cpp, uint32_t *tile, unsigned long *pitch, unsigned long flags) = NULL; +static void (*sym_drm_intel_bo_unreference)(drm_intel_bo *bo) = NULL; +static int (*sym_drmPrimeHandleToFD)(int fd, uint32_t handle, uint32_t flags, int *prime_fd) = NULL; +static void (*sym_drm_intel_bufmgr_destroy)(drm_intel_bufmgr *) = NULL; + +static struct exynos_device *(*sym_exynos_device_create)(int fd) = NULL; +static struct exynos_bo *(*sym_exynos_bo_create)(struct exynos_device *dev, size_t size, uint32_t flags) = NULL; +static void *(*sym_exynos_bo_map)(struct exynos_bo *bo) = NULL; +static void (*sym_exynos_bo_destroy)(struct exynos_bo *bo) = NULL; +static void (*sym_exynos_device_destroy)(struct exynos_device *) = NULL; + +static void +buffer_release(void *data, struct wl_buffer *buffer EINA_UNUSED) +{ + Ecore_Wl2_Buffer *b = data; + + b->busy = EINA_FALSE; + if (b->orphaned) ecore_wl2_buffer_destroy(b); +} + +static const struct wl_buffer_listener buffer_listener = +{ + buffer_release +}; + +static struct wl_buffer * +_evas_dmabuf_wl_buffer_from_dmabuf(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db) +{ + struct wl_buffer *buf; + struct zwp_linux_dmabuf_v1 *dmabuf; + struct zwp_linux_buffer_params_v1 *dp; + uint32_t flags = 0; + uint32_t format; + + if (db->alpha) + format = DRM_FORMAT_ARGB8888; + else + format = DRM_FORMAT_XRGB8888; + + dmabuf = ecore_wl2_display_dmabuf_get(ewd); + dp = zwp_linux_dmabuf_v1_create_params(dmabuf); + zwp_linux_buffer_params_v1_add(dp, db->fd, 0, 0, db->stride, 0, 0); + buf = zwp_linux_buffer_params_v1_create_immed(dp, db->w, db->h, + format, flags); + wl_buffer_add_listener(buf, &buffer_listener, db); + zwp_linux_buffer_params_v1_destroy(dp); + + return buf; +} + +static Buffer_Handle * +_intel_alloc(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd) +{ + uint32_t tile = I915_TILING_NONE; + drm_intel_bo *out; + + out = sym_drm_intel_bo_alloc_tiled(self->priv, name, w, h, 4, &tile, + stride, 0); + + if (!out) return NULL; + + if (tile != I915_TILING_NONE) goto err; + /* First try to allocate an mmapable buffer with O_RDWR, + * if that fails retry unmappable - if the compositor is + * using GL it won't need to mmap the buffer and this can + * work - otherwise it'll reject this buffer and we'll + * have to fall back to shm rendering. + */ + if (sym_drmPrimeHandleToFD(drm_fd, out->handle, + DRM_CLOEXEC | O_RDWR, fd) != 0) + if (sym_drmPrimeHandleToFD(drm_fd, out->handle, + DRM_CLOEXEC, fd) != 0) goto err; + + return (Buffer_Handle *)out; + +err: + sym_drm_intel_bo_unreference(out); + return NULL; +} + +static void * +_intel_map(Ecore_Wl2_Buffer *buf) +{ + drm_intel_bo *bo; + + bo = (drm_intel_bo *)buf->bh; + if (sym_drm_intel_bo_map(bo) != 0) return NULL; + return bo->virtual; +} + +static void +_intel_unmap(Ecore_Wl2_Buffer *buf) +{ + drm_intel_bo *bo; + + bo = (drm_intel_bo *)buf->bh; + sym_drm_intel_bo_unmap(bo); +} + +static void +_intel_discard(Ecore_Wl2_Buffer *buf) +{ + drm_intel_bo *bo; + + bo = (drm_intel_bo *)buf->bh; + sym_drm_intel_bo_unreference(bo); +} + +static void +_intel_manager_destroy() +{ + sym_drm_intel_bufmgr_destroy(buffer_manager->priv); +} + +static Eina_Bool +_intel_buffer_manager_setup(int fd) +{ + Eina_Bool fail = EINA_FALSE; + void *drm_intel_lib; + + drm_intel_lib = dlopen("libdrm_intel.so", RTLD_LAZY | RTLD_GLOBAL); + if (!drm_intel_lib) return EINA_FALSE; + + SYM(drm_intel_lib, drm_intel_bufmgr_gem_init); + SYM(drm_intel_lib, drm_intel_bo_unmap); + SYM(drm_intel_lib, drm_intel_bo_map); + SYM(drm_intel_lib, drm_intel_bo_alloc_tiled); + SYM(drm_intel_lib, drm_intel_bo_unreference); + SYM(drm_intel_lib, drm_intel_bufmgr_destroy); + SYM(drm_intel_lib, drmPrimeHandleToFD); + + if (fail) goto err; + + buffer_manager->priv = sym_drm_intel_bufmgr_gem_init(fd, 32); + if (!buffer_manager->priv) goto err; + + buffer_manager->alloc = _intel_alloc; + buffer_manager->to_buffer = _evas_dmabuf_wl_buffer_from_dmabuf; + buffer_manager->map = _intel_map; + buffer_manager->unmap = _intel_unmap; + buffer_manager->discard = _intel_discard; + buffer_manager->manager_destroy = _intel_manager_destroy; + buffer_manager->dl_handle = drm_intel_lib; + + return EINA_TRUE; + +err: + dlclose(drm_intel_lib); + return EINA_FALSE; +} + +static Buffer_Handle * +_exynos_alloc(Buffer_Manager *self, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd) +{ + size_t size = w * h * 4; + struct exynos_bo *out; + + *stride = w * 4; + out = sym_exynos_bo_create(self->priv, size, 0); + if (!out) return NULL; + /* First try to allocate an mmapable buffer with O_RDWR, + * if that fails retry unmappable - if the compositor is + * using GL it won't need to mmap the buffer and this can + * work - otherwise it'll reject this buffer and we'll + * have to fall back to shm rendering. + */ + if (sym_drmPrimeHandleToFD(drm_fd, out->handle, + DRM_CLOEXEC | O_RDWR, fd) != 0) + if (sym_drmPrimeHandleToFD(drm_fd, out->handle, + DRM_CLOEXEC, fd) != 0) goto err; + + return (Buffer_Handle *)out; + +err: + sym_exynos_bo_destroy(out); + return NULL; +} + +static void * +_exynos_map(Ecore_Wl2_Buffer *buf) +{ + struct exynos_bo *bo; + void *ptr; + + bo = (struct exynos_bo *)buf->bh; + ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, buf->fd, 0); + if (ptr == MAP_FAILED) return NULL; + return ptr; +} + +static void +_exynos_unmap(Ecore_Wl2_Buffer *buf) +{ + struct exynos_bo *bo; + + bo = (struct exynos_bo *)buf->bh; + munmap(buf->mapping, bo->size); +} + +static void +_exynos_discard(Ecore_Wl2_Buffer *buf) +{ + struct exynos_bo *bo; + + bo = (struct exynos_bo *)buf->bh; + sym_exynos_bo_destroy(bo); +} + +static void +_exynos_manager_destroy() +{ + sym_exynos_device_destroy(buffer_manager->priv); +} + +static Eina_Bool +_exynos_buffer_manager_setup(int fd) +{ + Eina_Bool fail = EINA_FALSE; + void *drm_exynos_lib; + struct exynos_bo *bo; + + drm_exynos_lib = dlopen("libdrm_exynos.so", RTLD_LAZY | RTLD_GLOBAL); + if (!drm_exynos_lib) return EINA_FALSE; + + SYM(drm_exynos_lib, exynos_device_create); + SYM(drm_exynos_lib, exynos_bo_create); + SYM(drm_exynos_lib, exynos_bo_map); + SYM(drm_exynos_lib, exynos_bo_destroy); + SYM(drm_exynos_lib, exynos_device_destroy); + SYM(drm_exynos_lib, drmPrimeHandleToFD); + + if (fail) goto err; + + buffer_manager->priv = sym_exynos_device_create(fd); + if (!buffer_manager->priv) goto err; + + /* _device_create succeeds on any arch, test harder */ + bo = sym_exynos_bo_create(buffer_manager->priv, 32, 0); + if (!bo) goto err; + + sym_exynos_bo_destroy(bo); + + buffer_manager->alloc = _exynos_alloc; + buffer_manager->to_buffer = _evas_dmabuf_wl_buffer_from_dmabuf; + buffer_manager->map = _exynos_map; + buffer_manager->unmap = _exynos_unmap; + buffer_manager->discard = _exynos_discard; + buffer_manager->manager_destroy = _exynos_manager_destroy; + buffer_manager->dl_handle = drm_exynos_lib; + return EINA_TRUE; + +err: + dlclose(drm_exynos_lib); + return EINA_FALSE; +} + +static Buffer_Handle * +_wl_shm_alloc(Buffer_Manager *self EINA_UNUSED, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd) +{ + Efl_Vpath_File *file_obj; + Eina_Tmpstr *fullname; + size_t size = w * h * 4; + void *out = NULL; + + file_obj = efl_vpath_manager_fetch(EFL_VPATH_MANAGER_CLASS, + "(:run:)/evas-wayland_shm-XXXXXX"); + *fd = eina_file_mkstemp(efl_vpath_file_result_get(file_obj), &fullname); + efl_del(file_obj); + if (*fd < 0) return NULL; + + unlink(fullname); + eina_tmpstr_del(fullname); + + *stride = w * 4; + if (ftruncate(*fd, size) < 0) goto err; + + out = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, *fd, 0); + if (out == MAP_FAILED) goto err; + + return out; + +err: + close(*fd); + return NULL; +} + +static void * +_wl_shm_map(Ecore_Wl2_Buffer *buf) +{ + return buf->bh; +} + +static void +_wl_shm_unmap(Ecore_Wl2_Buffer *buf EINA_UNUSED) +{ + /* wl_shm is mapped for its lifetime */ +} + +static void +_wl_shm_discard(Ecore_Wl2_Buffer *buf) +{ + munmap(buf->bh, buf->size); +} + +static void +_wl_shm_manager_destroy() +{ + /* Nop. */ +} + +static struct wl_buffer * +_wl_shm_to_buffer(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db) +{ + struct wl_buffer *buf; + struct wl_shm_pool *pool; + struct wl_shm *shm; + uint32_t format; + + if (db->alpha) + format = WL_SHM_FORMAT_ARGB8888; + else + format = WL_SHM_FORMAT_XRGB8888; + + shm = ecore_wl2_display_shm_get(ewd); + pool = wl_shm_create_pool(shm, db->fd, db->size); + buf = wl_shm_pool_create_buffer(pool, 0, db->w, db->h, db->stride, format); + wl_shm_pool_destroy(pool); + close(db->fd); + db->fd = -1; + wl_buffer_add_listener(buf, &buffer_listener, db); + return buf; +} + +static Eina_Bool +_wl_shm_buffer_manager_setup(int fd EINA_UNUSED) +{ + buffer_manager->alloc = _wl_shm_alloc; + buffer_manager->to_buffer = _wl_shm_to_buffer; + buffer_manager->map = _wl_shm_map; + buffer_manager->unmap = _wl_shm_unmap; + buffer_manager->discard = _wl_shm_discard; + buffer_manager->manager_destroy = _wl_shm_manager_destroy; + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_wl2_buffer_init(Ecore_Wl2_Buffer_Type types) +{ + int fd; + Eina_Bool dmabuf = types & ECORE_WL2_BUFFER_DMABUF; + Eina_Bool shm = types & ECORE_WL2_BUFFER_SHM; + Eina_Bool success = EINA_FALSE; + + if (buffer_manager) + { + buffer_manager->refcount++; + return EINA_TRUE; + } + + buffer_manager = calloc(1, sizeof(Buffer_Manager)); + if (!buffer_manager) goto err_alloc; + + fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC); + if (fd < 0) goto err_drm; + + if (!getenv("EVAS_WAYLAND_SHM_DISABLE_DMABUF")) + { + success = dmabuf && _intel_buffer_manager_setup(fd); + if (!success) success = dmabuf && _exynos_buffer_manager_setup(fd); + } + if (!success) success = shm && _wl_shm_buffer_manager_setup(fd); + if (!success) goto err_bm; + + drm_fd = fd; + buffer_manager->refcount = 1; + return EINA_TRUE; + +err_bm: + close(fd); +err_drm: + free(buffer_manager); +err_alloc: + return EINA_FALSE; +} + +static void +_buffer_manager_ref(void) +{ + buffer_manager->refcount++; +} + +static void +_buffer_manager_deref(void) +{ + buffer_manager->refcount--; + if (buffer_manager->refcount || !buffer_manager->destroyed) return; + + if (buffer_manager->manager_destroy) buffer_manager->manager_destroy(); + free(buffer_manager); + buffer_manager = NULL; + close(drm_fd); +} + +/* Currently no callers, but that will change... +static void +_buffer_manager_destroy(void) +{ + if (buffer_manager->destroyed) return; + buffer_manager->destroyed = EINA_TRUE; + _buffer_manager_deref(); +} +*/ + +static Buffer_Handle * +_buffer_manager_alloc(const char *name, int w, int h, unsigned long *stride, int32_t *fd) +{ + Buffer_Handle *out; + + _buffer_manager_ref(); + out = buffer_manager->alloc(buffer_manager, name, w, h, stride, fd); + if (!out) _buffer_manager_deref(); + return out; +} + +EAPI struct wl_buffer * +ecore_wl2_buffer_wl_buffer_get(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *buf) +{ + return buffer_manager->to_buffer(ewd, buf); +} + +EAPI void * +ecore_wl2_buffer_map(Ecore_Wl2_Buffer *buf) +{ + void *out; + + _buffer_manager_ref(); + out = buffer_manager->map(buf); + if (!out) _buffer_manager_deref(); + return out; +} + +EAPI void +ecore_wl2_buffer_unmap(Ecore_Wl2_Buffer *buf) +{ + buffer_manager->unmap(buf); + _buffer_manager_deref(); +} + +EAPI void +ecore_wl2_buffer_discard(Ecore_Wl2_Buffer *buf) +{ + buffer_manager->discard(buf); + _buffer_manager_deref(); +} + +EAPI void +ecore_wl2_buffer_unlock(Ecore_Wl2_Buffer *b) +{ + ecore_wl2_buffer_unmap(b); + b->mapping = NULL; + b->locked = EINA_FALSE; +} + +EAPI void +ecore_wl2_buffer_destroy(Ecore_Wl2_Buffer *b) +{ + if (!b) return; + + if (b->locked || b->busy) + { + b->orphaned = EINA_TRUE; + return; + } + if (b->fd != -1) close(b->fd); + if (b->mapping) ecore_wl2_buffer_unmap(b); + ecore_wl2_buffer_discard(b); + if (b->wl_buffer) wl_buffer_destroy(b->wl_buffer); + b->wl_buffer = NULL; + free(b); +} + +EAPI Ecore_Wl2_Buffer * +ecore_wl2_buffer_create(Ecore_Wl2_Display *ewd, int w, int h, Eina_Bool alpha) +{ + Ecore_Wl2_Buffer *out; + + out = calloc(1, sizeof(Ecore_Wl2_Buffer)); + if (!out) return NULL; + + out->fd = -1; + out->alpha = alpha; + out->bh = _buffer_manager_alloc("name", w, h, &out->stride, &out->fd); + if (!out->bh) + { + free(out); + return NULL; + } + out->w = w; + out->h = h; + out->size = out->stride * h; + + out->wl_buffer = ecore_wl2_buffer_wl_buffer_get(ewd, out); + + return out; +} diff --git a/src/modules/evas/engines/wayland_shm/evas_dmabuf.c b/src/modules/evas/engines/wayland_shm/evas_dmabuf.c index 68d5b11d41..b54424b3d6 100644 --- a/src/modules/evas/engines/wayland_shm/evas_dmabuf.c +++ b/src/modules/evas/engines/wayland_shm/evas_dmabuf.c @@ -4,68 +4,10 @@ #include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> -#include <dlfcn.h> -#include <drm_fourcc.h> -#include <intel_bufmgr.h> -#include <i915_drm.h> - -#include <exynos_drm.h> -#include <exynos_drmif.h> -#include <sys/mman.h> #include "linux-dmabuf-unstable-v1-client-protocol.h" -#define SYM(lib, xx) \ - do { \ - sym_## xx = dlsym(lib, #xx); \ - if (!(sym_ ## xx)) { \ - fail = EINA_TRUE; \ - } \ - } while (0) - -static int drm_fd = -1; - typedef struct _Dmabuf_Surface Dmabuf_Surface; - -typedef struct _Ecore_Wl2_Buffer Ecore_Wl2_Buffer; -typedef struct _Buffer_Handle Buffer_Handle; -typedef struct _Buffer_Manager Buffer_Manager; -struct _Buffer_Manager -{ - Buffer_Handle *(*alloc)(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd); - struct wl_buffer *(*to_buffer)(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db); - void *(*map)(Ecore_Wl2_Buffer *buf); - void (*unmap)(Ecore_Wl2_Buffer *buf); - void (*discard)(Ecore_Wl2_Buffer *buf); - void (*manager_destroy)(void); - void *priv; - void *dl_handle; - int refcount; - Eina_Bool destroyed; -}; - -static Buffer_Manager *buffer_manager = NULL; - -struct _Ecore_Wl2_Buffer -{ - struct wl_buffer *wl_buffer; - int size; - int w, h; - int age; - unsigned long stride; - Buffer_Handle *bh; - int fd; - void *mapping; - - int index; - Eina_Bool locked : 1; - Eina_Bool busy : 1; - Eina_Bool used : 1; - Eina_Bool orphaned : 1; - Eina_Bool alpha : 1; -}; - struct _Dmabuf_Surface { Surface *surface; @@ -79,492 +21,6 @@ struct _Dmabuf_Surface static void _internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface); static void _evas_dmabuf_surface_destroy(Surface *s); -static Ecore_Wl2_Buffer *ecore_wl2_buffer_create(Ecore_Wl2_Display *ewd, int w, int h, Eina_Bool alpha); -static void ecore_wl2_buffer_destroy(Ecore_Wl2_Buffer *b); - -static drm_intel_bufmgr *(*sym_drm_intel_bufmgr_gem_init)(int fd, int batch_size) = NULL; -static int (*sym_drm_intel_bo_unmap)(drm_intel_bo *bo) = NULL; -static int (*sym_drm_intel_bo_map)(drm_intel_bo *bo) = NULL; -static drm_intel_bo *(*sym_drm_intel_bo_alloc_tiled)(drm_intel_bufmgr *mgr, const char *name, int x, int y, int cpp, uint32_t *tile, unsigned long *pitch, unsigned long flags) = NULL; -static void (*sym_drm_intel_bo_unreference)(drm_intel_bo *bo) = NULL; -static int (*sym_drmPrimeHandleToFD)(int fd, uint32_t handle, uint32_t flags, int *prime_fd) = NULL; -static void (*sym_drm_intel_bufmgr_destroy)(drm_intel_bufmgr *) = NULL; - -static struct exynos_device *(*sym_exynos_device_create)(int fd) = NULL; -static struct exynos_bo *(*sym_exynos_bo_create)(struct exynos_device *dev, size_t size, uint32_t flags) = NULL; -static void *(*sym_exynos_bo_map)(struct exynos_bo *bo) = NULL; -static void (*sym_exynos_bo_destroy)(struct exynos_bo *bo) = NULL; -static void (*sym_exynos_device_destroy)(struct exynos_device *) = NULL; - -static void -buffer_release(void *data, struct wl_buffer *buffer EINA_UNUSED) -{ - Ecore_Wl2_Buffer *b = data; - - b->busy = EINA_FALSE; - if (b->orphaned) ecore_wl2_buffer_destroy(b); -} - -static const struct wl_buffer_listener buffer_listener = -{ - buffer_release -}; - -static struct wl_buffer * -_evas_dmabuf_wl_buffer_from_dmabuf(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db) -{ - struct wl_buffer *buf; - struct zwp_linux_dmabuf_v1 *dmabuf; - struct zwp_linux_buffer_params_v1 *dp; - uint32_t flags = 0; - uint32_t format; - - if (db->alpha) - format = DRM_FORMAT_ARGB8888; - else - format = DRM_FORMAT_XRGB8888; - - dmabuf = ecore_wl2_display_dmabuf_get(ewd); - dp = zwp_linux_dmabuf_v1_create_params(dmabuf); - zwp_linux_buffer_params_v1_add(dp, db->fd, 0, 0, db->stride, 0, 0); - buf = zwp_linux_buffer_params_v1_create_immed(dp, db->w, db->h, - format, flags); - wl_buffer_add_listener(buf, &buffer_listener, db); - zwp_linux_buffer_params_v1_destroy(dp); - - return buf; -} - -static Buffer_Handle * -_intel_alloc(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd) -{ - uint32_t tile = I915_TILING_NONE; - drm_intel_bo *out; - - out = sym_drm_intel_bo_alloc_tiled(self->priv, name, w, h, 4, &tile, - stride, 0); - - if (!out) return NULL; - - if (tile != I915_TILING_NONE) goto err; - /* First try to allocate an mmapable buffer with O_RDWR, - * if that fails retry unmappable - if the compositor is - * using GL it won't need to mmap the buffer and this can - * work - otherwise it'll reject this buffer and we'll - * have to fall back to shm rendering. - */ - if (sym_drmPrimeHandleToFD(drm_fd, out->handle, - DRM_CLOEXEC | O_RDWR, fd) != 0) - if (sym_drmPrimeHandleToFD(drm_fd, out->handle, - DRM_CLOEXEC, fd) != 0) goto err; - - return (Buffer_Handle *)out; - -err: - sym_drm_intel_bo_unreference(out); - return NULL; -} - -static void * -_intel_map(Ecore_Wl2_Buffer *buf) -{ - drm_intel_bo *bo; - - bo = (drm_intel_bo *)buf->bh; - if (sym_drm_intel_bo_map(bo) != 0) return NULL; - return bo->virtual; -} - -static void -_intel_unmap(Ecore_Wl2_Buffer *buf) -{ - drm_intel_bo *bo; - - bo = (drm_intel_bo *)buf->bh; - sym_drm_intel_bo_unmap(bo); -} - -static void -_intel_discard(Ecore_Wl2_Buffer *buf) -{ - drm_intel_bo *bo; - - bo = (drm_intel_bo *)buf->bh; - sym_drm_intel_bo_unreference(bo); -} - -static void -_intel_manager_destroy() -{ - sym_drm_intel_bufmgr_destroy(buffer_manager->priv); -} - -static Eina_Bool -_intel_buffer_manager_setup(int fd) -{ - Eina_Bool fail = EINA_FALSE; - void *drm_intel_lib; - - drm_intel_lib = dlopen("libdrm_intel.so", RTLD_LAZY | RTLD_GLOBAL); - if (!drm_intel_lib) return EINA_FALSE; - - SYM(drm_intel_lib, drm_intel_bufmgr_gem_init); - SYM(drm_intel_lib, drm_intel_bo_unmap); - SYM(drm_intel_lib, drm_intel_bo_map); - SYM(drm_intel_lib, drm_intel_bo_alloc_tiled); - SYM(drm_intel_lib, drm_intel_bo_unreference); - SYM(drm_intel_lib, drm_intel_bufmgr_destroy); - SYM(drm_intel_lib, drmPrimeHandleToFD); - - if (fail) goto err; - - buffer_manager->priv = sym_drm_intel_bufmgr_gem_init(fd, 32); - if (!buffer_manager->priv) goto err; - - buffer_manager->alloc = _intel_alloc; - buffer_manager->to_buffer = _evas_dmabuf_wl_buffer_from_dmabuf; - buffer_manager->map = _intel_map; - buffer_manager->unmap = _intel_unmap; - buffer_manager->discard = _intel_discard; - buffer_manager->manager_destroy = _intel_manager_destroy; - buffer_manager->dl_handle = drm_intel_lib; - - return EINA_TRUE; - -err: - dlclose(drm_intel_lib); - return EINA_FALSE; -} - -static Buffer_Handle * -_exynos_alloc(Buffer_Manager *self, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd) -{ - size_t size = w * h * 4; - struct exynos_bo *out; - - *stride = w * 4; - out = sym_exynos_bo_create(self->priv, size, 0); - if (!out) return NULL; - /* First try to allocate an mmapable buffer with O_RDWR, - * if that fails retry unmappable - if the compositor is - * using GL it won't need to mmap the buffer and this can - * work - otherwise it'll reject this buffer and we'll - * have to fall back to shm rendering. - */ - if (sym_drmPrimeHandleToFD(drm_fd, out->handle, - DRM_CLOEXEC | O_RDWR, fd) != 0) - if (sym_drmPrimeHandleToFD(drm_fd, out->handle, - DRM_CLOEXEC, fd) != 0) goto err; - - return (Buffer_Handle *)out; - -err: - sym_exynos_bo_destroy(out); - return NULL; -} - -static void * -_exynos_map(Ecore_Wl2_Buffer *buf) -{ - struct exynos_bo *bo; - void *ptr; - - bo = (struct exynos_bo *)buf->bh; - ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, buf->fd, 0); - if (ptr == MAP_FAILED) return NULL; - return ptr; -} - -static void -_exynos_unmap(Ecore_Wl2_Buffer *buf) -{ - struct exynos_bo *bo; - - bo = (struct exynos_bo *)buf->bh; - munmap(buf->mapping, bo->size); -} - -static void -_exynos_discard(Ecore_Wl2_Buffer *buf) -{ - struct exynos_bo *bo; - - bo = (struct exynos_bo *)buf->bh; - sym_exynos_bo_destroy(bo); -} - -static void -_exynos_manager_destroy() -{ - sym_exynos_device_destroy(buffer_manager->priv); -} - -static Eina_Bool -_exynos_buffer_manager_setup(int fd) -{ - Eina_Bool fail = EINA_FALSE; - void *drm_exynos_lib; - struct exynos_bo *bo; - - drm_exynos_lib = dlopen("libdrm_exynos.so", RTLD_LAZY | RTLD_GLOBAL); - if (!drm_exynos_lib) return EINA_FALSE; - - SYM(drm_exynos_lib, exynos_device_create); - SYM(drm_exynos_lib, exynos_bo_create); - SYM(drm_exynos_lib, exynos_bo_map); - SYM(drm_exynos_lib, exynos_bo_destroy); - SYM(drm_exynos_lib, exynos_device_destroy); - SYM(drm_exynos_lib, drmPrimeHandleToFD); - - if (fail) goto err; - - buffer_manager->priv = sym_exynos_device_create(fd); - if (!buffer_manager->priv) goto err; - - /* _device_create succeeds on any arch, test harder */ - bo = sym_exynos_bo_create(buffer_manager->priv, 32, 0); - if (!bo) goto err; - - sym_exynos_bo_destroy(bo); - - buffer_manager->alloc = _exynos_alloc; - buffer_manager->to_buffer = _evas_dmabuf_wl_buffer_from_dmabuf; - buffer_manager->map = _exynos_map; - buffer_manager->unmap = _exynos_unmap; - buffer_manager->discard = _exynos_discard; - buffer_manager->manager_destroy = _exynos_manager_destroy; - buffer_manager->dl_handle = drm_exynos_lib; - return EINA_TRUE; - -err: - dlclose(drm_exynos_lib); - return EINA_FALSE; -} - -static Buffer_Handle * -_wl_shm_alloc(Buffer_Manager *self EINA_UNUSED, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd) -{ - Efl_Vpath_File *file_obj; - Eina_Tmpstr *fullname; - size_t size = w * h * 4; - void *out = NULL; - - file_obj = efl_vpath_manager_fetch(EFL_VPATH_MANAGER_CLASS, - "(:run:)/evas-wayland_shm-XXXXXX"); - *fd = eina_file_mkstemp(efl_vpath_file_result_get(file_obj), &fullname); - efl_del(file_obj); - if (*fd < 0) return NULL; - - unlink(fullname); - eina_tmpstr_del(fullname); - - *stride = w * 4; - if (ftruncate(*fd, size) < 0) goto err; - - out = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, *fd, 0); - if (out == MAP_FAILED) goto err; - - return out; - -err: - close(*fd); - return NULL; -} - -static void * -_wl_shm_map(Ecore_Wl2_Buffer *buf) -{ - return buf->bh; -} - -static void -_wl_shm_unmap(Ecore_Wl2_Buffer *buf EINA_UNUSED) -{ - /* wl_shm is mapped for its lifetime */ -} - -static void -_wl_shm_discard(Ecore_Wl2_Buffer *buf) -{ - munmap(buf->bh, buf->size); -} - -static void -_wl_shm_manager_destroy() -{ - /* Nop. */ -} - -static struct wl_buffer * -_wl_shm_to_buffer(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db) -{ - struct wl_buffer *buf; - struct wl_shm_pool *pool; - struct wl_shm *shm; - uint32_t format; - - if (db->alpha) - format = WL_SHM_FORMAT_ARGB8888; - else - format = WL_SHM_FORMAT_XRGB8888; - - shm = ecore_wl2_display_shm_get(ewd); - pool = wl_shm_create_pool(shm, db->fd, db->size); - buf = wl_shm_pool_create_buffer(pool, 0, db->w, db->h, db->stride, format); - wl_shm_pool_destroy(pool); - close(db->fd); - db->fd = -1; - wl_buffer_add_listener(buf, &buffer_listener, db); - return buf; -} - -static Eina_Bool -_wl_shm_buffer_manager_setup(int fd EINA_UNUSED) -{ - buffer_manager->alloc = _wl_shm_alloc; - buffer_manager->to_buffer = _wl_shm_to_buffer; - buffer_manager->map = _wl_shm_map; - buffer_manager->unmap = _wl_shm_unmap; - buffer_manager->discard = _wl_shm_discard; - buffer_manager->manager_destroy = _wl_shm_manager_destroy; - return EINA_TRUE; -} - -static Eina_Bool -ecore_wl2_buffer_init(Ecore_Wl2_Buffer_Type types) -{ - int fd; - Eina_Bool dmabuf = types & ECORE_WL2_BUFFER_DMABUF; - Eina_Bool shm = types & ECORE_WL2_BUFFER_SHM; - Eina_Bool success = EINA_FALSE; - - if (buffer_manager) - { - buffer_manager->refcount++; - return EINA_TRUE; - } - - buffer_manager = calloc(1, sizeof(Buffer_Manager)); - if (!buffer_manager) goto err_alloc; - - fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC); - if (fd < 0) goto err_drm; - - if (!getenv("EVAS_WAYLAND_SHM_DISABLE_DMABUF")) - { - success = dmabuf && _intel_buffer_manager_setup(fd); - if (!success) success = dmabuf && _exynos_buffer_manager_setup(fd); - } - if (!success) success = shm && _wl_shm_buffer_manager_setup(fd); - if (!success) goto err_bm; - - drm_fd = fd; - buffer_manager->refcount = 1; - return EINA_TRUE; - -err_bm: - close(fd); -err_drm: - free(buffer_manager); -err_alloc: - return EINA_FALSE; -} - -static void -_buffer_manager_ref(void) -{ - buffer_manager->refcount++; -} - -static void -_buffer_manager_deref(void) -{ - buffer_manager->refcount--; - if (buffer_manager->refcount || !buffer_manager->destroyed) return; - - if (buffer_manager->manager_destroy) buffer_manager->manager_destroy(); - free(buffer_manager); - buffer_manager = NULL; - close(drm_fd); -} - -/* Currently no callers, but that will change... -static void -_buffer_manager_destroy(void) -{ - if (buffer_manager->destroyed) return; - buffer_manager->destroyed = EINA_TRUE; - _buffer_manager_deref(); -} -*/ - -static Buffer_Handle * -_buffer_manager_alloc(const char *name, int w, int h, unsigned long *stride, int32_t *fd) -{ - Buffer_Handle *out; - - _buffer_manager_ref(); - out = buffer_manager->alloc(buffer_manager, name, w, h, stride, fd); - if (!out) _buffer_manager_deref(); - return out; -} - -static struct wl_buffer * -ecore_wl2_buffer_wl_buffer_get(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *buf) -{ - return buffer_manager->to_buffer(ewd, buf); -} - -static void * -ecore_wl2_buffer_map(Ecore_Wl2_Buffer *buf) -{ - void *out; - - _buffer_manager_ref(); - out = buffer_manager->map(buf); - if (!out) _buffer_manager_deref(); - return out; -} - -static void -ecore_wl2_buffer_unmap(Ecore_Wl2_Buffer *buf) -{ - buffer_manager->unmap(buf); - _buffer_manager_deref(); -} - -static void -ecore_wl2_buffer_discard(Ecore_Wl2_Buffer *buf) -{ - buffer_manager->discard(buf); - _buffer_manager_deref(); -} - -static void -ecore_wl2_buffer_unlock(Ecore_Wl2_Buffer *b) -{ - ecore_wl2_buffer_unmap(b); - b->mapping = NULL; - b->locked = EINA_FALSE; -} - -static void -ecore_wl2_buffer_destroy(Ecore_Wl2_Buffer *b) -{ - if (!b) return; - - if (b->locked || b->busy) - { - b->orphaned = EINA_TRUE; - return; - } - if (b->fd != -1) close(b->fd); - if (b->mapping) ecore_wl2_buffer_unmap(b); - ecore_wl2_buffer_discard(b); - if (b->wl_buffer) wl_buffer_destroy(b->wl_buffer); - b->wl_buffer = NULL; - free(b); -} static void _evas_dmabuf_surface_reconfigure(Surface *s, int w, int h, uint32_t flags EINA_UNUSED, Eina_Bool force) @@ -690,31 +146,6 @@ _evas_dmabuf_surface_post(Surface *s, Eina_Rectangle *rects, unsigned int count) ecore_wl2_window_commit(win, EINA_TRUE); } -static Ecore_Wl2_Buffer * -ecore_wl2_buffer_create(Ecore_Wl2_Display *ewd, int w, int h, Eina_Bool alpha) -{ - Ecore_Wl2_Buffer *out; - - out = calloc(1, sizeof(Ecore_Wl2_Buffer)); - if (!out) return NULL; - - out->fd = -1; - out->alpha = alpha; - out->bh = _buffer_manager_alloc("name", w, h, &out->stride, &out->fd); - if (!out->bh) - { - free(out); - return NULL; - } - out->w = w; - out->h = h; - out->size = out->stride * h; - - out->wl_buffer = ecore_wl2_buffer_wl_buffer_get(ewd, out); - - return out; -} - static void _internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface) { diff --git a/src/modules/evas/engines/wayland_shm/evas_engine.h b/src/modules/evas/engines/wayland_shm/evas_engine.h index 338b9ba2df..726f424102 100644 --- a/src/modules/evas/engines/wayland_shm/evas_engine.h +++ b/src/modules/evas/engines/wayland_shm/evas_engine.h @@ -75,14 +75,6 @@ extern int _evas_engine_way_shm_log_dom; typedef struct _Shm_Surface Shm_Surface; typedef struct _Dmabuf_Surface Dmabuf_Surface; -typedef enum _Ecore_Wl2_Buffer_Type Ecore_Wl2_Buffer_Type; -enum _Ecore_Wl2_Buffer_Type -{ - ECORE_WL2_BUFFER_NONE = 0, - ECORE_WL2_BUFFER_SHM = 1, - ECORE_WL2_BUFFER_DMABUF = 2 -}; - typedef struct _Surface Surface; struct _Surface { |