From 8b621775619b9959fe952b095b3baaa7aaa99572 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 22 Jun 2015 10:23:54 -0400 Subject: [PATCH] ecore-buffer: Add ecore_buffer library to EFL. Summary: Ecore_Buffer is abstraction of graphic buffer. it supports backend of shm, x11_dri2 and x11_dri3 for now, and this library also provides method to share buffers between processes. Ecore_Buffer_Provider and Ecore_Buffer_Consumer is for this, sharing buffer. provider draws something in to Ecore_Buffer, and consumer receives and displays it. the binary, bq_mgr is a connection maker for buffer provider and consumer. it can be included Enlightenment as a deamon later. @feature Test Plan: 1. Configure with --enable-ecore-buffer and --enable-always-build-examples to build examples. 2. Run bq_mgr, it connects consumer and provider. 3. Run ecore_buffer_provider_example and ecore_buffer_consumer_example Reviewers: lsj119, gwanglim, cedric, zmike, jpeg, raster, devilhorns Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D2197 --- Makefile.am | 1 + configure.ac | 72 ++ pc/.gitignore | 1 + pc/ecore-buffer.pc.in | 12 + src/Makefile.am | 1 + src/Makefile_Ecore_Buffer.am | 113 +++ src/bin/ecore_buffer/.gitignore | 1 + src/bin/ecore_buffer/bq_mgr.c | 899 ++++++++++++++++++ src/bin/ecore_buffer/bq_mgr_protocol.c | 131 +++ src/bin/ecore_buffer/bq_mgr_protocol.h | 247 +++++ src/examples/ecore/.gitignore | 3 + src/examples/ecore/Makefile.am | 19 + .../ecore/ecore_buffer_consumer_example.c | 192 ++++ src/examples/ecore/ecore_buffer_example.c | 128 +++ .../ecore/ecore_buffer_provider_example.c | 274 ++++++ src/lib/ecore_buffer/Ecore_Buffer.h | 629 ++++++++++++ src/lib/ecore_buffer/Ecore_Buffer_Queue.h | 449 +++++++++ src/lib/ecore_buffer/bq_mgr_protocol.c | 131 +++ src/lib/ecore_buffer/bq_mgr_protocol.h | 329 +++++++ src/lib/ecore_buffer/buffer_queue.c | 153 +++ src/lib/ecore_buffer/buffer_queue.h | 23 + src/lib/ecore_buffer/ecore_buffer.c | 491 ++++++++++ src/lib/ecore_buffer/ecore_buffer_con.c | 253 +++++ src/lib/ecore_buffer/ecore_buffer_con.h | 20 + src/lib/ecore_buffer/ecore_buffer_consumer.c | 417 ++++++++ src/lib/ecore_buffer/ecore_buffer_private.h | 31 + src/lib/ecore_buffer/ecore_buffer_provider.c | 391 ++++++++ .../ecore_buffer/ecore_buffer_queue_main.c | 54 ++ src/lib/ecore_buffer/shared_buffer.c | 148 +++ src/lib/ecore_buffer/shared_buffer.h | 41 + .../ecore_buffer/shm/ecore_buffer_shm.c | 172 ++++ .../x11_dri2/ecore_buffer_x11_dri2.c | 538 +++++++++++ .../x11_dri3/ecore_buffer_x11_dri3.c | 602 ++++++++++++ 33 files changed, 6966 insertions(+) create mode 100644 pc/ecore-buffer.pc.in create mode 100644 src/Makefile_Ecore_Buffer.am create mode 100644 src/bin/ecore_buffer/.gitignore create mode 100644 src/bin/ecore_buffer/bq_mgr.c create mode 100644 src/bin/ecore_buffer/bq_mgr_protocol.c create mode 100644 src/bin/ecore_buffer/bq_mgr_protocol.h create mode 100644 src/examples/ecore/ecore_buffer_consumer_example.c create mode 100644 src/examples/ecore/ecore_buffer_example.c create mode 100644 src/examples/ecore/ecore_buffer_provider_example.c create mode 100644 src/lib/ecore_buffer/Ecore_Buffer.h create mode 100644 src/lib/ecore_buffer/Ecore_Buffer_Queue.h create mode 100644 src/lib/ecore_buffer/bq_mgr_protocol.c create mode 100644 src/lib/ecore_buffer/bq_mgr_protocol.h create mode 100644 src/lib/ecore_buffer/buffer_queue.c create mode 100644 src/lib/ecore_buffer/buffer_queue.h create mode 100644 src/lib/ecore_buffer/ecore_buffer.c create mode 100644 src/lib/ecore_buffer/ecore_buffer_con.c create mode 100644 src/lib/ecore_buffer/ecore_buffer_con.h create mode 100644 src/lib/ecore_buffer/ecore_buffer_consumer.c create mode 100644 src/lib/ecore_buffer/ecore_buffer_private.h create mode 100644 src/lib/ecore_buffer/ecore_buffer_provider.c create mode 100644 src/lib/ecore_buffer/ecore_buffer_queue_main.c create mode 100644 src/lib/ecore_buffer/shared_buffer.c create mode 100644 src/lib/ecore_buffer/shared_buffer.h create mode 100644 src/modules/ecore_buffer/shm/ecore_buffer_shm.c create mode 100644 src/modules/ecore_buffer/x11_dri2/ecore_buffer_x11_dri2.c create mode 100644 src/modules/ecore_buffer/x11_dri3/ecore_buffer_x11_dri3.c diff --git a/Makefile.am b/Makefile.am index 34927d7290..d02db5e5b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -140,6 +140,7 @@ pc/ecore-imf.pc \ pc/ecore-imf-evas.pc \ pc/ecore-evas.pc \ pc/ecore-avahi.pc \ +pc/ecore-buffer.pc \ pc/ector.pc \ pc/embryo.pc \ pc/eio.pc \ diff --git a/configure.ac b/configure.ac index 9b0e8cace5..1673471d91 100644 --- a/configure.ac +++ b/configure.ac @@ -1705,6 +1705,17 @@ AC_ARG_ENABLE([tile-rotate], ], [have_tile_rotate="no"]) +# Ecore Buffer +AC_ARG_ENABLE([ecore-buffer], + [AS_HELP_STRING([--enable-ecore-buffer],[enable ecore-buffer. @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_ecore_buffer="yes" + else + want_ecore_buffer="no" + fi + ], + [want_ecore_buffer="no"]) # Image Loaders @@ -4587,6 +4598,65 @@ AC_ARG_ENABLE([i-really-know-what-i-am-doing-and-that-this-will-probably-break-t ], [ BARF_OK="xno" ]) +#### Ecore_Buffer +build_ecore_buffer_x11_dri2="no" +build_ecore_buffer_x11_dri3="no" +EFL_LIB_START_OPTIONAL([Ecore_Buffer], [test "${want_ecore_buffer}" = "yes"]) +### Checks for libraries +EFL_INTERNAL_DEPEND_PKG([ECORE_BUFFER], [eina]) +EFL_INTERNAL_DEPEND_PKG([ECORE_BUFFER], [eo]) +EFL_INTERNAL_DEPEND_PKG([ECORE_BUFFER], [ecore]) +EFL_DEPEND_PKG([ECORE_BUFFER], [WAYLAND], + [wayland-server >= 1.5.0 wayland-client >= 1.5.0]) + +PKG_CHECK_MODULES([X11_DRI_COMMON], + [ + libtbm >= 1.1.0, + libdrm >= 2.4.35, + ], + [have_x11_dri_common_pkgs="yes"], + [have_x11_dri_common_pkgs="no"] +) + +if test "x$have_x11_dri_common_pkgs" = "xyes" ; then + EFL_INTERNAL_DEPEND_PKG([ECORE_BUFFER], [ecore_x]) + + PKG_CHECK_MODULES([X11_DRI2], [libdri2], + [have_x11_dri2_pkgs="yes"], + [have_x11_dri2_pkgs="no"]) + PKG_CHECK_MODULES([X11_DRI3], + [ + xshmfence, + xcb, + x11-xcb, + xcb-sync, + xcb-dri3 + ], + [have_x11_dri3_pkgs="yes"], + [have_x11_dri3_pkgs="no"]) +fi + +if test "x${have_x11_dri2_pkgs}" = "xyes" ; then + build_ecore_buffer_x11_dri2="yes" + AC_DEFINE(BUILD_ECORE_BUFFER_X11_DRI2, 1, [Support for X11_DRI2 Backend in Ecore_Buffer]) +fi + +if test "x${have_x11_dri3_pkgs}" = "xyes" ; then + build_ecore_buffer_x11_dri3="yes" + AC_DEFINE(BUILD_ECORE_BUFFER_X11_DRI3, 1, [Support for X11_DRI3 Backend in Ecore_Buffer]) +fi +EFL_EVAL_PKGS([ECORE_BUFFER]) + +EFL_ADD_FEATURE([ECORE_BUFFER], [shm], ["yes"]) +EFL_ADD_FEATURE([ECORE_BUFFER], [x11_dri2], [${build_ecore_buffer_x11_dri2}]) +EFL_ADD_FEATURE([ECORE_BUFFER], [x11_dri3], [${build_ecore_buffer_x11_dri3}]) + +EFL_LIB_END_OPTIONAL([Ecore_Buffer]) + +AM_CONDITIONAL([BUILD_ECORE_BUFFER_X11_DRI2], [test "${build_ecore_buffer_x11_dri2}" = "xyes"]) +AM_CONDITIONAL([BUILD_ECORE_BUFFER_X11_DRI3], [test "${build_ecore_buffer_x11_dri3}" = "xyes"]) + +#### End of Ecore_Buffer AC_CONFIG_FILES([ Makefile @@ -4667,6 +4737,7 @@ pc/ecore-imf-evas.pc pc/ecore-audio.pc pc/ecore-audio-cxx.pc pc/ecore-avahi.pc +pc/ecore-buffer.pc pc/ector.pc pc/embryo.pc pc/eio.pc @@ -4827,6 +4898,7 @@ echo "Ecore_X.........: ${with_x11} (${features_ecore_x})" echo "Ecore_SDL.......: $want_sdl" echo "Ecore_Wayland...: $want_wayland" echo "IVI-Shell.......: $want_wayland_ivi_shell" +echo "Ecore_Buffer....: $want_ecore_buffer (${features_ecore_buffer})" if test "${have_linux}" = "yes"; then echo "Ecore_FB........: $want_fb (${features_ecore_fb})" elif test "${have_ps3}" = "yes"; then diff --git a/pc/.gitignore b/pc/.gitignore index f13d852670..5aadf61079 100644 --- a/pc/.gitignore +++ b/pc/.gitignore @@ -17,6 +17,7 @@ /ecore-win32.pc /ecore-x.pc /ecore.pc +/ecore-buffer.pc /ector.pc /edje.pc /eet.pc diff --git a/pc/ecore-buffer.pc.in b/pc/ecore-buffer.pc.in new file mode 100644 index 0000000000..a23a2a444f --- /dev/null +++ b/pc/ecore-buffer.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ecore-buffer +Description: E core library, graphic buffer module +Requires.private: @requirements_pc_ecore_buffer@ +Version: @VERSION@ +Libs: -L${libdir} -lecore_buffer +Libs.private: @requirements_libs_ecore_buffer@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/ecore-buffer-@VMAJ@ diff --git a/src/Makefile.am b/src/Makefile.am index 0522fa33ca..dccc538af2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,6 +54,7 @@ include Makefile_Ecore_Avahi.am include Makefile_Embryo.am include Makefile_Eio.am include Makefile_Efreet.am +include Makefile_Ecore_Buffer.am include Makefile_EPhysics.am include Makefile_Edje.am include Makefile_Emotion.am diff --git a/src/Makefile_Ecore_Buffer.am b/src/Makefile_Ecore_Buffer.am new file mode 100644 index 0000000000..c357c5cd00 --- /dev/null +++ b/src/Makefile_Ecore_Buffer.am @@ -0,0 +1,113 @@ +if HAVE_ECORE_BUFFER + +### Library + +lib_LTLIBRARIES += lib/ecore_buffer/libecore_buffer.la + +installed_ecorebuffermainheadersdir = $(includedir)/ecore-buffer-@VMAJ@ +dist_installed_ecorebuffermainheaders_DATA = \ +lib/ecore_buffer/Ecore_Buffer.h \ +lib/ecore_buffer/Ecore_Buffer_Queue.h + +lib_ecore_buffer_libecore_buffer_la_SOURCES = \ +lib/ecore_buffer/bq_mgr_protocol.c \ +lib/ecore_buffer/buffer_queue.c \ +lib/ecore_buffer/shared_buffer.c \ +lib/ecore_buffer/ecore_buffer.c \ +lib/ecore_buffer/ecore_buffer_queue_main.c \ +lib/ecore_buffer/ecore_buffer_con.c \ +lib/ecore_buffer/ecore_buffer_provider.c \ +lib/ecore_buffer/ecore_buffer_consumer.c + +lib_ecore_buffer_libecore_buffer_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +@ECORE_BUFFER_CFLAGS@ + +lib_ecore_buffer_libecore_buffer_la_LIBADD = @ECORE_BUFFER_LIBS@ +lib_ecore_buffer_libecore_buffer_la_DEPENDENCIES = @ECORE_BUFFER_INTERNAL_LIBS@ +lib_ecore_buffer_libecore_buffer_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ + +### Binary +bqmgr_bindir=$(libdir)/ecore_buffer/bin/$(MODULE_ARCH) +bqmgr_bin_PROGRAMS = bin/ecore_buffer/bq_mgr + +bin_ecore_buffer_bq_mgr_SOURCES = \ +bin/ecore_buffer/bq_mgr_protocol.c \ +bin/ecore_buffer/bq_mgr.c + +bin_ecore_buffer_bq_mgr_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +@ECORE_BUFFER_CFLAGS@ +bin_ecore_buffer_bq_mgr_LDADD = @USE_ECORE_INTERNAL_LIBS@ @USE_ECORE_BUFFER_LIBS@ +bin_ecore_buffer_bq_mgr_DEPENDENCIES = @USE_ECORE_INTERNAL_LIBS@ @USE_ECORE_BUFFER_INTERNAL_LIBS@ + +### Backends + +ecorebuffershmdir = $(libdir)/ecore_buffer/modules/shm/$(MODULE_ARCH) +ecorebuffershm_LTLIBRARIES = modules/ecore_buffer/shm/module.la + +modules_ecore_buffer_shm_module_la_SOURCES = \ + modules/ecore_buffer/shm/ecore_buffer_shm.c +modules_ecore_buffer_shm_module_la_CPPFLAGS = \ + -I$(top_builddir)/src/lib/efl \ + @ECORE_BUFFER_CFLAGS@ \ + -I$(top_srcdir)/src/modules/ecore_buffer/shm +modules_ecore_buffer_shm_module_la_LIBADD = \ + @ECORE_BUFFER_LIBS@ \ + @USE_ECORE_BUFFER_INTERNAL_LIBS@ +modules_ecore_buffer_shm_module_la_DEPENDENCIES = \ + @USE_ECORE_BUFFER_INTERNAL_LIBS@ +modules_ecore_buffer_shm_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ +modules_ecore_buffer_shm_module_la_LIBTOOLFLAGS = --tag=disable-static + +if BUILD_ECORE_BUFFER_X11_DRI2 +ecorebufferx11dri2dir = $(libdir)/ecore_buffer/modules/x11_dri2/$(MODULE_ARCH) +ecorebufferx11dri2_LTLIBRARIES = modules/ecore_buffer/x11_dri2/module.la + +modules_ecore_buffer_x11_dri2_module_la_SOURCES = \ + modules/ecore_buffer/x11_dri2/ecore_buffer_x11_dri2.c +modules_ecore_buffer_x11_dri2_module_la_CPPFLAGS = \ + -I$(top_builddir)/src/lib/efl \ + @ECORE_BUFFER_CFLAGS@ \ + @X11_DRI_COMMON_CFLAGS@ \ + @X11_DRI2_CFLAGS@ \ + -I$(top_srcdir)/src/modules/ecore_buffer/x11_dri2 +modules_ecore_buffer_x11_dri2_module_la_LIBADD = \ + @ECORE_BUFFER_LIBS@ \ + @USE_ECORE_BUFFER_INTERNAL_LIBS@ \ + @X11_DRI_COMMON_LIBS@ \ + @X11_DRI2_LIBS@ +modules_ecore_buffer_x11_dri2_module_la_DEPENDENCIES = \ + @USE_ECORE_X_INTERNAL_LIBS@ \ + @USE_ECORE_BUFFER_INTERNAL_LIBS@ +modules_ecore_buffer_x11_dri2_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ +modules_ecore_buffer_x11_dri2_module_la_LIBTOOLFLAGS = --tag=disable-static +endif + +if BUILD_ECORE_BUFFER_X11_DRI3 +ecorebufferx11dri3dir = $(libdir)/ecore_buffer/modules/x11_dri3/$(MODULE_ARCH) +ecorebufferx11dri3_LTLIBRARIES = modules/ecore_buffer/x11_dri3/module.la + +modules_ecore_buffer_x11_dri3_module_la_SOURCES = \ + modules/ecore_buffer/x11_dri3/ecore_buffer_x11_dri3.c +modules_ecore_buffer_x11_dri3_module_la_CPPFLAGS = \ + -I$(top_builddir)/src/lib/efl \ + @ECORE_BUFFER_CFLAGS@ \ + @X11_DRI_COMMON_CFLAGS@ \ + @X11_DRI3_CFLAGS@ \ + -I$(top_srcdir)/src/modules/ecore_buffer/x11_dri3 +modules_ecore_buffer_x11_dri3_module_la_LIBADD = \ + @ECORE_BUFFER_LIBS@ \ + @USE_ECORE_BUFFER_INTERNAL_LIBS@ \ + @X11_DRI_COMMON_LIBS@ \ + @X11_DRI3_LIBS@ +modules_ecore_buffer_x11_dri3_module_la_DEPENDENCIES = \ + @USE_ECORE_X_INTERNAL_LIBS@ \ + @USE_ECORE_BUFFER_INTERNAL_LIBS@ +modules_ecore_buffer_x11_dri3_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ +modules_ecore_buffer_x11_dri3_module_la_LIBTOOLFLAGS = --tag=disable-static +endif + +endif diff --git a/src/bin/ecore_buffer/.gitignore b/src/bin/ecore_buffer/.gitignore new file mode 100644 index 0000000000..846a9e2122 --- /dev/null +++ b/src/bin/ecore_buffer/.gitignore @@ -0,0 +1 @@ +/bq_mgr diff --git a/src/bin/ecore_buffer/bq_mgr.c b/src/bin/ecore_buffer/bq_mgr.c new file mode 100644 index 0000000000..4cb3c1f759 --- /dev/null +++ b/src/bin/ecore_buffer/bq_mgr.c @@ -0,0 +1,899 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bq_mgr_protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +#define BQ_LOG(f, x...) printf("[ES|%30.30s|%04d] " f "\n", __func__, __LINE__, ##x) +#define BQ_DEBUG(f, x...) if (debug) printf("[ES|%30.30s|%04d] " f "\n", __func__, __LINE__, ##x) +#define BQ_OBJECT_NEW(x, f) bq_object_new(sizeof(x), ((Bq_Object_Free_Func)(f))) +#define BQ_OBJECT(x) ((Bq_Object *)(x)) +#define BQ_OBJECT_RESOURCE(x) (((Bq_Object *)(x))->resource) + +typedef void (*Bq_Object_Free_Func) (void *obj); + +typedef struct _Bq_Object Bq_Object; +typedef struct _Bq_Mgr Bq_Mgr; +typedef struct _Bq_Buffer_Queue Bq_Buffer_Queue; +typedef struct _Bq_Buffer_Consumer Bq_Buffer_Consumer; +typedef struct _Bq_Buffer_Provider Bq_Buffer_Provider; +typedef struct _Bq_Buffer Bq_Buffer; +typedef enum _Bq_Buffer_Type Bq_Buffer_Type; + +struct _Bq_Object +{ + int ref; + Bq_Object_Free_Func free_fn; + Eina_Bool deleted; + struct wl_resource *resource; +}; + +struct _Bq_Mgr +{ + Bq_Object bq_obj; + + struct wl_display *wdpy; + struct wl_event_source *signals[3]; + + /*BufferQueue manager*/ + struct wl_global *bq_mgr; + Eina_Hash *buffer_queues; +}; + + +struct _Bq_Buffer_Queue +{ + Bq_Object bq_obj; + Eina_Hash *link; + + char *name; + struct wl_signal connect; + + Bq_Buffer_Consumer *consumer; + Bq_Buffer_Provider *provider; + Eina_Inlist *buffers; +}; + +struct _Bq_Buffer_Consumer +{ + Bq_Object bq_obj; + Bq_Buffer_Queue *buffer_queue; + + int32_t queue_size; + int32_t width; + int32_t height; +}; + +struct _Bq_Buffer_Provider +{ + Bq_Object bq_obj; + Bq_Buffer_Queue *buffer_queue; +}; + +enum _Bq_Buffer_Type +{ + bq_BUFFER_TYPE_ID, + bq_BUFFER_TYPE_FD, +}; + +struct _Bq_Buffer +{ + Bq_Object bq_obj; /*Dont use wl_resource in bq_obj*/ + EINA_INLIST; + + struct wl_resource *consumer; + struct wl_resource *provider; + uint32_t serial; + + char *engine; + Bq_Buffer_Type type; + int32_t width; + int32_t height; + int32_t format; + uint32_t flags; + + int32_t id; + int32_t offset0; + int32_t stride0; + int32_t offset1; + int32_t stride1; + int32_t offset2; + int32_t stride2; +}; + +static Eina_Bool debug; + +static void * +bq_object_new(size_t size, Bq_Object_Free_Func fn) +{ + Bq_Object *o = calloc(1, size); + + if ((!o)) return NULL; + + o->ref = 1; + o->free_fn = fn; + + return o; +} + +static int +bq_object_ref(Bq_Object *o) +{ + o->ref++; + + return o->ref; +} + +static int +bq_object_unref(Bq_Object *o) +{ + o->ref--; + + if (o->ref <= 0 || o->deleted) + { + if (o->free_fn) + o->free_fn(o); + + free(o); + } + + return o->ref; +} + +static int +bq_object_free(Bq_Object *o) +{ + if (!o) return 0; + if (o->deleted) return 0; + + o->deleted = EINA_TRUE; + + return bq_object_unref(o); +} + +static void +bq_mgr_buffer_queue_free(Bq_Buffer_Queue *bq) +{ + Bq_Buffer *buf; + + if (!bq) return; + + BQ_DEBUG("destroy buffer queue : %s\n", bq->name); + + if (bq->consumer) + { + wl_resource_destroy(BQ_OBJECT_RESOURCE(bq->consumer)); + bq->consumer = NULL; + } + + if (bq->provider) + { + wl_resource_destroy(BQ_OBJECT_RESOURCE(bq->provider)); + bq->provider = NULL; + } + + while (bq->buffers) + { + buf = EINA_INLIST_CONTAINER_GET(bq->buffers,Bq_Buffer); + bq->buffers = eina_inlist_remove(bq->buffers, bq->buffers); + if (buf->consumer) + { + wl_resource_destroy(buf->consumer); + buf->consumer = NULL; + } + + if (buf->provider) + { + wl_resource_destroy(buf->provider); + buf->provider = NULL; + } + } + + if (bq->link) + { + eina_hash_del(bq->link, bq->name, bq); + bq->link = NULL; + } + if (bq->name) + { + free(bq->name); + bq->name = NULL; + } +} + +static Bq_Buffer_Queue* +bq_mgr_buffer_queue_new(Bq_Mgr *bq_mgr, const char *name) +{ + Bq_Buffer_Queue *bq; + + bq = eina_hash_find(bq_mgr->buffer_queues, name); + if (bq) + { + bq_object_ref(BQ_OBJECT(bq)); + return bq; + } + + bq = BQ_OBJECT_NEW(Bq_Buffer_Queue, bq_mgr_buffer_queue_free); + EINA_SAFETY_ON_NULL_RETURN_VAL(bq, NULL); + + bq->link = bq_mgr->buffer_queues; + bq->name = strdup(name); + if (!eina_hash_add(bq->link,bq->name,bq)) + { + bq_object_free(BQ_OBJECT(bq)); + return NULL; + } + + wl_signal_init(&bq->connect); + bq->buffers = NULL; + return bq; +} + +static void +bq_mgr_buffer_consumer_release_buffer(struct wl_client *client EINA_UNUSED, + struct wl_resource *resource, + struct wl_resource *buffer) +{ + Bq_Buffer_Queue *bq; + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Provider *bq_provider; + Bq_Buffer *bq_buffer; + + bq_consumer = (Bq_Buffer_Consumer*)wl_resource_get_user_data(resource); + bq_buffer = (Bq_Buffer*)wl_resource_get_user_data(buffer); + bq = bq_consumer->buffer_queue; + bq_provider = bq->provider; + + if (bq_provider && bq_buffer->provider) + { + bq_provider_send_add_buffer(BQ_OBJECT_RESOURCE(bq_provider), + bq_buffer->provider, bq_buffer->serial); + } +} + +static const struct bq_consumer_interface _bq_consumer_interface = { + bq_mgr_buffer_consumer_release_buffer +}; + +static void +bq_mgr_buffer_consumer_destroy(struct wl_resource *resource) +{ + Bq_Buffer_Consumer *bq_consumer = wl_resource_get_user_data(resource); + Bq_Buffer_Provider *bq_provider; + Bq_Buffer_Queue *bq; + Bq_Buffer *buf; + + if (!bq_consumer) return; + + BQ_DEBUG("destroy buffer consumer : %s\n", bq_consumer->buffer_queue->name); + + bq = bq_consumer->buffer_queue; + bq_provider = bq->provider; + + bq->consumer = NULL; + BQ_OBJECT_RESOURCE(bq_consumer) = NULL; + + if (bq_provider) + { + bq_provider_send_disconnected(BQ_OBJECT_RESOURCE(bq_provider)); + } + + while (bq->buffers) + { + buf = EINA_INLIST_CONTAINER_GET(bq->buffers,Bq_Buffer); + bq->buffers = eina_inlist_remove(bq->buffers,bq->buffers); + + BQ_DEBUG("destroy BUFFER : %d\n", buf->type); + if (buf->consumer) + { + wl_resource_destroy(buf->consumer); + buf->consumer = NULL; + bq_object_unref(BQ_OBJECT(buf)); + } + + if (buf->provider) + { + wl_resource_destroy(buf->provider); + buf->provider = NULL; + bq_object_unref(BQ_OBJECT(buf)); + } + } + + bq_object_unref(BQ_OBJECT(bq_consumer)); + bq_object_unref(BQ_OBJECT(bq)); +} + +static void +bq_mgr_buffer_destroy(struct wl_resource *resource) +{ + Bq_Buffer *buf = wl_resource_get_user_data(resource); + + if (resource == buf->consumer) + { + BQ_DEBUG("destroy buffer : consumer\n"); + } + else if (resource == buf->provider) + { + BQ_DEBUG("destroy buffer : provider\n"); + } +} + +static void +bq_buffer_create_consumer_side(Bq_Buffer_Consumer *bq_consumer, Bq_Buffer *bq_buffer) +{ + if (!bq_consumer) return; + + bq_buffer->consumer = wl_resource_create(wl_resource_get_client(BQ_OBJECT_RESOURCE(bq_consumer)), + &bq_buffer_interface, 1, 0); + wl_resource_set_implementation(bq_buffer->consumer, NULL, bq_buffer, bq_mgr_buffer_destroy); + bq_object_ref(BQ_OBJECT(bq_buffer)); + + bq_consumer_send_buffer_attached(BQ_OBJECT_RESOURCE(bq_consumer), + bq_buffer->consumer, + bq_buffer->engine, + bq_buffer->width, + bq_buffer->height, + bq_buffer->format, + bq_buffer->flags); +} + +static void +bq_buffer_set_consumer_side(Bq_Buffer_Consumer *bq_consumer, Bq_Buffer *bq_buffer) +{ + if (!bq_consumer) return; + EINA_SAFETY_ON_NULL_RETURN(bq_buffer); + EINA_SAFETY_ON_NULL_RETURN(bq_buffer->consumer); + + if (bq_buffer->type == bq_BUFFER_TYPE_ID) + bq_consumer_send_set_buffer_id(BQ_OBJECT_RESOURCE(bq_consumer), + bq_buffer->consumer, + bq_buffer->id, + bq_buffer->offset0, + bq_buffer->stride0, + bq_buffer->offset1, + bq_buffer->stride1, + bq_buffer->offset2, + bq_buffer->stride2); + else + { + bq_consumer_send_set_buffer_fd(BQ_OBJECT_RESOURCE(bq_consumer), + bq_buffer->consumer, + bq_buffer->id, + bq_buffer->offset0, + bq_buffer->stride0, + bq_buffer->offset1, + bq_buffer->stride1, + bq_buffer->offset2, + bq_buffer->stride2); + close(bq_buffer->id); + } +} + +static void +bq_mgr_buffer_queue_create_consumer(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + const char *name, + int32_t queue_size, + int32_t width, + int32_t height) +{ + Bq_Mgr *bq_mgr = (Bq_Mgr*)wl_resource_get_user_data(resource); + Bq_Buffer_Queue *bq; + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Provider *bq_provider; + Bq_Buffer *buf; + + EINA_SAFETY_ON_NULL_RETURN(bq_mgr); + + bq = bq_mgr_buffer_queue_new(bq_mgr,name); + EINA_SAFETY_ON_NULL_RETURN(bq); + + if (bq->consumer) + { + bq_object_unref(BQ_OBJECT(bq)); + wl_resource_post_error(resource, + BQ_MGR_ERROR_ALREADY_USED, + "%s consumer already used",name); + return; + } + + bq_consumer = BQ_OBJECT_NEW(Bq_Buffer_Consumer, NULL); + EINA_SAFETY_ON_NULL_RETURN(bq_consumer); + BQ_OBJECT_RESOURCE(bq_consumer) = wl_resource_create(client, + &bq_consumer_interface, + 1, id); + if (!BQ_OBJECT_RESOURCE(bq_consumer)) + { + bq_object_unref(BQ_OBJECT(bq_consumer)); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(BQ_OBJECT_RESOURCE(bq_consumer), + &_bq_consumer_interface, + bq_consumer, + bq_mgr_buffer_consumer_destroy); + + bq_consumer->buffer_queue = bq; + bq_consumer->queue_size = queue_size; + bq_consumer->width = width; + bq_consumer->height = height; + + bq_provider = bq->provider; + bq->consumer = bq_consumer; + if (bq_provider) + { + bq_provider_send_connected(BQ_OBJECT_RESOURCE(bq_provider), + queue_size, width, height); + bq_consumer_send_connected(BQ_OBJECT_RESOURCE(bq_consumer)); + } + + EINA_INLIST_FOREACH(bq->buffers,buf) + { + bq_buffer_create_consumer_side(bq_consumer, buf); + bq_buffer_set_consumer_side(bq_consumer, buf); + } +} + +static void +bq_buffer_free(Bq_Buffer *buf) +{ + if (buf->engine) + free(buf->engine); +} + +static void +bq_mgr_buffer_provider_attatch_buffer(struct wl_client *client, + struct wl_resource *resource, + uint32_t buffer, + const char *engine, + int32_t width, + int32_t height, + int32_t format, + uint32_t flags) +{ + Bq_Buffer_Provider *bq_provider = wl_resource_get_user_data(resource); + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Queue *bq; + Bq_Buffer *bq_buffer; + + EINA_SAFETY_ON_NULL_RETURN(bq_provider); + bq = bq_provider->buffer_queue; + bq_consumer = bq->consumer; + + bq_buffer = BQ_OBJECT_NEW(Bq_Buffer, bq_buffer_free); + bq_buffer->provider = wl_resource_create(client, &bq_buffer_interface, 1, buffer); + wl_resource_set_implementation(bq_buffer->provider, NULL, bq_buffer, bq_mgr_buffer_destroy); + + if (!bq_buffer->provider) + { + wl_client_post_no_memory(client); + bq_object_unref(BQ_OBJECT(bq_buffer)); + return; + } + + bq_buffer->engine = strdup(engine); + bq_buffer->width = width; + bq_buffer->height = height; + bq_buffer->format = format; + bq_buffer->flags = flags; + + bq->buffers = eina_inlist_append(bq->buffers,EINA_INLIST_GET(bq_buffer)); + BQ_DEBUG("add BUFFER : %d\n", bq_buffer->type); + + bq_buffer_create_consumer_side(bq_consumer, bq_buffer); + +} + +static void +bq_mgr_buffer_provider_set_buffer_id(struct wl_client *client EINA_UNUSED, + struct wl_resource *resource, + struct wl_resource *buffer, + int32_t id, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2) +{ + Bq_Buffer_Provider *bq_provider = wl_resource_get_user_data(resource); + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Queue *bq; + Bq_Buffer *bq_buffer; + + EINA_SAFETY_ON_NULL_RETURN(bq_provider); + bq = bq_provider->buffer_queue; + bq_consumer = bq->consumer; + bq_buffer = wl_resource_get_user_data(buffer); + EINA_SAFETY_ON_NULL_RETURN(bq_buffer); + + bq_buffer->type = bq_BUFFER_TYPE_ID; + bq_buffer->id = id; + bq_buffer->offset0 = offset0; + bq_buffer->stride0 = stride0; + bq_buffer->offset1 = offset1; + bq_buffer->stride1 = stride1; + bq_buffer->offset2 = offset2; + bq_buffer->stride2 = stride2; + + bq_buffer_set_consumer_side(bq_consumer, bq_buffer); +} + +static void +bq_mgr_buffer_provider_set_buffer_fd(struct wl_client *client EINA_UNUSED, + struct wl_resource *resource, + struct wl_resource *buffer, + int32_t fd, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2) +{ + Bq_Buffer_Provider *bq_provider = wl_resource_get_user_data(resource); + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Queue *bq; + Bq_Buffer *bq_buffer; + + EINA_SAFETY_ON_NULL_RETURN(bq_provider); + bq = bq_provider->buffer_queue; + bq_consumer = bq->consumer; + bq_buffer = wl_resource_get_user_data(buffer); + EINA_SAFETY_ON_NULL_RETURN(bq_buffer); + + bq_buffer->type = bq_BUFFER_TYPE_FD; + bq_buffer->id = fd; + bq_buffer->offset0 = offset0; + bq_buffer->stride0 = stride0; + bq_buffer->offset1 = offset1; + bq_buffer->stride1 = stride1; + bq_buffer->offset2 = offset2; + bq_buffer->stride2 = stride2; + + bq_buffer_set_consumer_side(bq_consumer, bq_buffer); +} + + +static void +bq_mgr_buffer_provider_detach_buffer(struct wl_client *client EINA_UNUSED, + struct wl_resource *resource, + struct wl_resource *buffer) +{ + Bq_Buffer_Provider *bq_provider = wl_resource_get_user_data(resource); + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Queue *bq; + Bq_Buffer *bq_buffer; + + EINA_SAFETY_ON_NULL_RETURN(bq_provider); + bq = bq_provider->buffer_queue; + bq_consumer = bq->consumer; + bq_buffer = wl_resource_get_user_data(buffer); + + if (bq_consumer) + { + bq_consumer_send_buffer_detached(BQ_OBJECT_RESOURCE(bq_consumer), + bq_buffer->consumer); + wl_resource_destroy(bq_buffer->consumer); + bq_object_unref(BQ_OBJECT(bq_buffer)); + } + + wl_resource_destroy(bq_buffer->provider); + bq->buffers = eina_inlist_remove(bq->buffers,EINA_INLIST_GET(bq_buffer)); + bq_object_unref(BQ_OBJECT(bq_buffer)); +} + +static void +bq_mgr_buffer_provider_enqueue_buffer(struct wl_client *client EINA_UNUSED, + struct wl_resource *resource, + struct wl_resource *buffer, + uint32_t serial) +{ + Bq_Buffer_Provider *bq_provider = wl_resource_get_user_data(resource); + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer_Queue *bq; + Bq_Buffer *bq_buffer; + + EINA_SAFETY_ON_NULL_RETURN(bq_provider); + bq = bq_provider->buffer_queue; + bq_consumer = bq->consumer; + if (!bq_consumer) + { + wl_resource_post_error(BQ_OBJECT_RESOURCE(bq_consumer), + BQ_PROVIDER_ERROR_CONNECTION, + "Not connected:%s", bq->name); + return; + } + + bq_buffer = wl_resource_get_user_data(buffer); + EINA_SAFETY_ON_NULL_RETURN(bq_buffer); + bq_buffer->serial = serial; + + bq_consumer_send_add_buffer(BQ_OBJECT_RESOURCE(bq_consumer), + bq_buffer->consumer, + bq_buffer->serial); +} + +static const struct bq_provider_interface _bq_provider_interface = { + bq_mgr_buffer_provider_attatch_buffer, + bq_mgr_buffer_provider_set_buffer_id, + bq_mgr_buffer_provider_set_buffer_fd, + bq_mgr_buffer_provider_detach_buffer, + bq_mgr_buffer_provider_enqueue_buffer +}; + +static void +bq_mgr_buffer_provider_destroy(struct wl_resource *resource) +{ + Bq_Buffer_Queue *bq; + Bq_Buffer_Provider *bq_provider = wl_resource_get_user_data(resource); + Bq_Buffer_Consumer *bq_consumer; + Bq_Buffer *buf; + + EINA_SAFETY_ON_NULL_RETURN(bq_provider); + BQ_DEBUG("destroy buffer provider : %s\n", bq_provider->buffer_queue->name); + bq = bq_provider->buffer_queue; + bq_consumer = bq->consumer; + + BQ_OBJECT_RESOURCE(bq_provider) = NULL; + bq->provider = NULL; + + while (bq->buffers) + { + buf = EINA_INLIST_CONTAINER_GET(bq->buffers, Bq_Buffer); + bq->buffers = eina_inlist_remove(bq->buffers, bq->buffers); + + if (buf->consumer) + { + bq_consumer_send_buffer_detached(BQ_OBJECT_RESOURCE(bq_consumer), buf->consumer); + wl_resource_destroy(buf->consumer); + buf->consumer = NULL; + bq_object_unref(BQ_OBJECT(buf)); + } + + if (buf->provider) + { + wl_resource_destroy(buf->provider); + buf->provider = NULL; + bq_object_unref(BQ_OBJECT(buf)); + } + } + + if (bq_consumer) + { + if (BQ_OBJECT_RESOURCE(bq_consumer)) + bq_consumer_send_disconnected(BQ_OBJECT_RESOURCE(bq_consumer)); + } + + bq_object_unref(BQ_OBJECT(bq_provider)); + bq_object_unref(BQ_OBJECT(bq)); +} + +static void +bq_mgr_buffer_queue_create_provider(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + const char *name) +{ + Bq_Mgr *bq_mgr = (Bq_Mgr*)wl_resource_get_user_data(resource); + Bq_Buffer_Queue *bq; + Bq_Buffer_Provider *bq_provider; + Bq_Buffer_Consumer *bq_consumer; + + EINA_SAFETY_ON_NULL_RETURN(bq_mgr); + + bq = bq_mgr_buffer_queue_new(bq_mgr,name); + EINA_SAFETY_ON_NULL_RETURN(bq); + + if (bq->provider) + { + bq_object_unref(BQ_OBJECT(bq)); + wl_resource_post_error(resource, + BQ_MGR_ERROR_ALREADY_USED, + "%s rpovider already used",name); + return; + } + + bq_provider = BQ_OBJECT_NEW(Bq_Buffer_Provider, NULL); + EINA_SAFETY_ON_NULL_GOTO(bq_provider, on_error); + + BQ_OBJECT_RESOURCE(bq_provider)= wl_resource_create(client, + &bq_provider_interface, + 1, id); + EINA_SAFETY_ON_NULL_GOTO(BQ_OBJECT_RESOURCE(bq_provider), on_error); + + wl_resource_set_implementation(BQ_OBJECT_RESOURCE(bq_provider), + &_bq_provider_interface, + bq_provider, + bq_mgr_buffer_provider_destroy); + + bq_provider->buffer_queue = bq; + bq->provider = bq_provider; + bq_consumer = bq->consumer; + if (bq_consumer) + { + /*Send connect*/ + bq_consumer_send_connected(BQ_OBJECT_RESOURCE(bq_consumer)); + bq_provider_send_connected(BQ_OBJECT_RESOURCE(bq_provider), + bq_consumer->queue_size, + bq_consumer->width, bq_consumer->height); + } + + return; + +on_error: + if (bq) bq_object_unref(BQ_OBJECT(bq)); + if (bq_provider) bq_object_unref(BQ_OBJECT(bq_provider)); + wl_client_post_no_memory(client); +} + +static const struct bq_mgr_interface _bq_mgr_interface = +{ + bq_mgr_buffer_queue_create_consumer, + bq_mgr_buffer_queue_create_provider +}; + +static void +bq_mgr_buffer_queue_bind(struct wl_client *client, void *data, + uint32_t version EINA_UNUSED, uint32_t id) +{ + Bq_Mgr *bq_mgr = (Bq_Mgr*)data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &bq_mgr_interface, + 1, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, + &_bq_mgr_interface, + bq_mgr, NULL); +} + +Eina_Bool +bq_mgr_buffer_queue_manager_init(Bq_Mgr *bq_mgr) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(bq_mgr,EINA_FALSE); + bq_mgr->bq_mgr = wl_global_create(bq_mgr->wdpy + ,&bq_mgr_interface,1 + ,bq_mgr + ,bq_mgr_buffer_queue_bind); + + EINA_SAFETY_ON_NULL_RETURN_VAL(bq_mgr->bq_mgr,EINA_FALSE); + + bq_mgr->buffer_queues = eina_hash_string_superfast_new(NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(bq_mgr->buffer_queues,EINA_FALSE); + + return EINA_TRUE; +} + +static const Ecore_Getopt optdesc = +{ + "tbm_daemon", + "%prog [options]", + "0.1.0", + "(C) Samsung", + "BSD 2-Clause", + "Tizen Buffer Manager Daemon", + EINA_FALSE, + { + ECORE_GETOPT_STORE_STR('s', "socket_name", + "socket name"), + ECORE_GETOPT_STORE_BOOL('d',"debug","enable debug log"), + ECORE_GETOPT_VERSION('v', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +static int +bq_mgr_on_term_signal(int signal_number, void *data) +{ + Bq_Mgr *bq_mgr = data; + + BQ_LOG("caught signal %d\n", signal_number); + wl_display_terminate(bq_mgr->wdpy); + + return 1; +} + +static void +bq_mgr_free(Bq_Mgr *bq_mgr) +{ + int i; + + for (i = ARRAY_LENGTH(bq_mgr->signals) - 1; i >= 0; i--) + { + if (bq_mgr->signals[i]) + wl_event_source_remove(bq_mgr->signals[i]); + } + + if (bq_mgr->wdpy) + wl_display_destroy(bq_mgr->wdpy); +} + +static Bq_Mgr* +bq_mgr_new(char *sock_name) +{ + static char *default_sock_name = "bq_mgr_daemon"; + Bq_Mgr *bq_mgr = BQ_OBJECT_NEW(Bq_Mgr, bq_mgr_free); + struct wl_event_loop *loop; + + if (!bq_mgr) return NULL; + + bq_mgr->wdpy = wl_display_create(); + loop = wl_display_get_event_loop(bq_mgr->wdpy); + EINA_SAFETY_ON_NULL_GOTO(loop, on_err); + + bq_mgr->signals[0] = wl_event_loop_add_signal(loop, SIGTERM, bq_mgr_on_term_signal, bq_mgr); + bq_mgr->signals[1] = wl_event_loop_add_signal(loop, SIGINT, bq_mgr_on_term_signal, bq_mgr); + bq_mgr->signals[2] = wl_event_loop_add_signal(loop, SIGQUIT, bq_mgr_on_term_signal, bq_mgr); + + if (!sock_name) + sock_name = default_sock_name; + wl_display_add_socket(bq_mgr->wdpy, sock_name); + + return bq_mgr; + +on_err: + bq_object_free(BQ_OBJECT(bq_mgr)); + return NULL; +} + +int +main(int argc, char **argv) +{ + Bq_Mgr *bq_mgr = NULL; + int res, ret = EXIT_FAILURE; + char *opt_path = NULL; + Eina_Bool quit = EINA_FALSE; + Ecore_Getopt_Value values[] = + { + ECORE_GETOPT_VALUE_STR(opt_path), + ECORE_GETOPT_VALUE_BOOL(debug), + ECORE_GETOPT_VALUE_BOOL(quit), + ECORE_GETOPT_VALUE_BOOL(quit), + ECORE_GETOPT_VALUE_NONE + }; + + eina_init(); + + res = ecore_getopt_parse(&optdesc, + values, + argc, argv); + + if ((res < 0) || (quit)) goto finish; + + if (opt_path) + BQ_LOG("socket_name : %s\n", opt_path); + + bq_mgr = bq_mgr_new(opt_path); + if (!bq_mgr) goto finish; + + if (!bq_mgr_buffer_queue_manager_init(bq_mgr)) + { + bq_mgr_free(bq_mgr); + goto finish; + } + + wl_display_run(bq_mgr->wdpy); + + ret = EXIT_SUCCESS; +finish: + eina_shutdown(); + bq_object_free(BQ_OBJECT(bq_mgr)); + + return ret; +} diff --git a/src/bin/ecore_buffer/bq_mgr_protocol.c b/src/bin/ecore_buffer/bq_mgr_protocol.c new file mode 100644 index 0000000000..fe8b98c9bc --- /dev/null +++ b/src/bin/ecore_buffer/bq_mgr_protocol.c @@ -0,0 +1,131 @@ +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface bq_buffer_interface; +extern const struct wl_interface bq_consumer_interface; +extern const struct wl_interface bq_provider_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + &bq_consumer_interface, + NULL, + NULL, + NULL, + NULL, + &bq_provider_interface, + NULL, + &bq_buffer_interface, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + &bq_buffer_interface, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + &bq_buffer_interface, + NULL, + &bq_buffer_interface, + NULL, +}; + +static const struct wl_message bq_mgr_requests[] = { + { "create_consumer", "nsiii", types + 3 }, + { "create_provider", "ns", types + 8 }, +}; + +WL_EXPORT const struct wl_interface bq_mgr_interface = { + "bq_mgr", 1, + 2, bq_mgr_requests, + 0, NULL, +}; + +static const struct wl_message bq_consumer_requests[] = { + { "release_buffer", "o", types + 10 }, +}; + +static const struct wl_message bq_consumer_events[] = { + { "connected", "", types + 0 }, + { "disconnected", "", types + 0 }, + { "buffer_attached", "nsiiiu", types + 11 }, + { "set_buffer_id", "oiiiiiii", types + 17 }, + { "set_buffer_fd", "ohiiiiii", types + 25 }, + { "buffer_detached", "o", types + 33 }, + { "add_buffer", "ou", types + 34 }, +}; + +WL_EXPORT const struct wl_interface bq_consumer_interface = { + "bq_consumer", 1, + 1, bq_consumer_requests, + 7, bq_consumer_events, +}; + +static const struct wl_message bq_provider_requests[] = { + { "attach_buffer", "nsiiiu", types + 36 }, + { "set_buffer_id", "oiiiiiii", types + 42 }, + { "set_buffer_fd", "ohiiiiii", types + 50 }, + { "detach_buffer", "o", types + 58 }, + { "enqueue_buffer", "ou", types + 59 }, +}; + +static const struct wl_message bq_provider_events[] = { + { "connected", "iii", types + 0 }, + { "disconnected", "", types + 0 }, + { "add_buffer", "ou", types + 61 }, +}; + +WL_EXPORT const struct wl_interface bq_provider_interface = { + "bq_provider", 1, + 5, bq_provider_requests, + 3, bq_provider_events, +}; + +WL_EXPORT const struct wl_interface bq_buffer_interface = { + "bq_buffer", 1, + 0, NULL, + 0, NULL, +}; + diff --git a/src/bin/ecore_buffer/bq_mgr_protocol.h b/src/bin/ecore_buffer/bq_mgr_protocol.h new file mode 100644 index 0000000000..b2d7bcc775 --- /dev/null +++ b/src/bin/ecore_buffer/bq_mgr_protocol.h @@ -0,0 +1,247 @@ +#ifndef BQ_MGR_SERVER_PROTOCOL_H +#define BQ_MGR_SERVER_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-server.h" + +struct wl_client; +struct wl_resource; + +struct bq_mgr; +struct bq_consumer; +struct bq_provider; +struct bq_buffer; + +extern const struct wl_interface bq_mgr_interface; +extern const struct wl_interface bq_consumer_interface; +extern const struct wl_interface bq_provider_interface; +extern const struct wl_interface bq_buffer_interface; + +#ifndef BQ_MGR_ERROR_ENUM +#define BQ_MGR_ERROR_ENUM +enum bq_mgr_error { + BQ_MGR_ERROR_INVALID_PERMISSION = 0, + BQ_MGR_ERROR_INVALID_NAME = 1, + BQ_MGR_ERROR_ALREADY_USED = 2, +}; +#endif /* BQ_MGR_ERROR_ENUM */ + +struct bq_mgr_interface { + /** + * create_consumer - (none) + * @id: (none) + * @name: (none) + * @queue_size: (none) + * @width: (none) + * @height: (none) + */ + void (*create_consumer)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + const char *name, + int32_t queue_size, + int32_t width, + int32_t height); + /** + * create_provider - (none) + * @id: (none) + * @name: (none) + */ + void (*create_provider)(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + const char *name); +}; + + +struct bq_consumer_interface { + /** + * release_buffer - (none) + * @buffer: (none) + */ + void (*release_buffer)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer); +}; + +#define BQ_CONSUMER_CONNECTED 0 +#define BQ_CONSUMER_DISCONNECTED 1 +#define BQ_CONSUMER_BUFFER_ATTACHED 2 +#define BQ_CONSUMER_SET_BUFFER_ID 3 +#define BQ_CONSUMER_SET_BUFFER_FD 4 +#define BQ_CONSUMER_BUFFER_DETACHED 5 +#define BQ_CONSUMER_ADD_BUFFER 6 + +#define BQ_CONSUMER_CONNECTED_SINCE_VERSION 1 +#define BQ_CONSUMER_DISCONNECTED_SINCE_VERSION 1 +#define BQ_CONSUMER_BUFFER_ATTACHED_SINCE_VERSION 1 +#define BQ_CONSUMER_SET_BUFFER_ID_SINCE_VERSION 1 +#define BQ_CONSUMER_SET_BUFFER_FD_SINCE_VERSION 1 +#define BQ_CONSUMER_BUFFER_DETACHED_SINCE_VERSION 1 +#define BQ_CONSUMER_ADD_BUFFER_SINCE_VERSION 1 + +static inline void +bq_consumer_send_connected(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_CONNECTED); +} + +static inline void +bq_consumer_send_disconnected(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_DISCONNECTED); +} + +static inline void +bq_consumer_send_buffer_attached(struct wl_resource *resource_, struct wl_resource *buffer, const char *engine, int32_t width, int32_t height, int32_t format, uint32_t flags) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_BUFFER_ATTACHED, buffer, engine, width, height, format, flags); +} + +static inline void +bq_consumer_send_set_buffer_id(struct wl_resource *resource_, struct wl_resource *buffer, int32_t id, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_SET_BUFFER_ID, buffer, id, offset0, stride0, offset1, stride1, offset2, stride2); +} + +static inline void +bq_consumer_send_set_buffer_fd(struct wl_resource *resource_, struct wl_resource *buffer, int32_t fd, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_SET_BUFFER_FD, buffer, fd, offset0, stride0, offset1, stride1, offset2, stride2); +} + +static inline void +bq_consumer_send_buffer_detached(struct wl_resource *resource_, struct wl_resource *buffer) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_BUFFER_DETACHED, buffer); +} + +static inline void +bq_consumer_send_add_buffer(struct wl_resource *resource_, struct wl_resource *buffer, uint32_t serial) +{ + wl_resource_post_event(resource_, BQ_CONSUMER_ADD_BUFFER, buffer, serial); +} + +#ifndef BQ_PROVIDER_ERROR_ENUM +#define BQ_PROVIDER_ERROR_ENUM +enum bq_provider_error { + BQ_PROVIDER_ERROR_OVERFLOW_QUEUE_SIZE = 0, + BQ_PROVIDER_ERROR_CONNECTION = 1, +}; +#endif /* BQ_PROVIDER_ERROR_ENUM */ + +struct bq_provider_interface { + /** + * attach_buffer - (none) + * @buffer: (none) + * @engine: (none) + * @width: (none) + * @height: (none) + * @format: (none) + * @flags: (none) + */ + void (*attach_buffer)(struct wl_client *client, + struct wl_resource *resource, + uint32_t buffer, + const char *engine, + int32_t width, + int32_t height, + int32_t format, + uint32_t flags); + /** + * set_buffer_id - (none) + * @buffer: (none) + * @id: (none) + * @offset0: (none) + * @stride0: (none) + * @offset1: (none) + * @stride1: (none) + * @offset2: (none) + * @stride2: (none) + */ + void (*set_buffer_id)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer, + int32_t id, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2); + /** + * set_buffer_fd - (none) + * @buffer: (none) + * @fd: (none) + * @offset0: (none) + * @stride0: (none) + * @offset1: (none) + * @stride1: (none) + * @offset2: (none) + * @stride2: (none) + */ + void (*set_buffer_fd)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer, + int32_t fd, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2); + /** + * detach_buffer - (none) + * @buffer: (none) + */ + void (*detach_buffer)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer); + /** + * enqueue_buffer - (none) + * @buffer: (none) + * @serial: (none) + */ + void (*enqueue_buffer)(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *buffer, + uint32_t serial); +}; + +#define BQ_PROVIDER_CONNECTED 0 +#define BQ_PROVIDER_DISCONNECTED 1 +#define BQ_PROVIDER_ADD_BUFFER 2 + +#define BQ_PROVIDER_CONNECTED_SINCE_VERSION 1 +#define BQ_PROVIDER_DISCONNECTED_SINCE_VERSION 1 +#define BQ_PROVIDER_ADD_BUFFER_SINCE_VERSION 1 + +static inline void +bq_provider_send_connected(struct wl_resource *resource_, int32_t queue_size, int32_t width, int32_t height) +{ + wl_resource_post_event(resource_, BQ_PROVIDER_CONNECTED, queue_size, width, height); +} + +static inline void +bq_provider_send_disconnected(struct wl_resource *resource_) +{ + wl_resource_post_event(resource_, BQ_PROVIDER_DISCONNECTED); +} + +static inline void +bq_provider_send_add_buffer(struct wl_resource *resource_, struct wl_resource *buffer, uint32_t serial) +{ + wl_resource_post_event(resource_, BQ_PROVIDER_ADD_BUFFER, buffer, serial); +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/examples/ecore/.gitignore b/src/examples/ecore/.gitignore index acc3750839..8b84fca973 100644 --- a/src/examples/ecore/.gitignore +++ b/src/examples/ecore/.gitignore @@ -43,3 +43,6 @@ /ecore_thread_example /ecore_time_functions_example /ecore_timer_example +/ecore_buffer_example +/ecore_buffer_consumer_example +/ecore_buffer_provider_example diff --git a/src/examples/ecore/Makefile.am b/src/examples/ecore/Makefile.am index f73c4f9e3b..179408e369 100644 --- a/src/examples/ecore/Makefile.am +++ b/src/examples/ecore/Makefile.am @@ -8,6 +8,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/eo \ -I$(top_srcdir)/src/lib/evas \ -I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_buffer \ -I$(top_srcdir)/src/lib/ecore_input \ -I$(top_srcdir)/src/lib/ecore_input_evas \ -I$(top_srcdir)/src/lib/ecore_file \ @@ -35,6 +36,9 @@ AM_CPPFLAGS = \ EXTRA_PROGRAMS = \ ecore_animator_example \ +ecore_buffer_example \ +ecore_buffer_consumer_example \ +ecore_buffer_provider_example \ ecore_client_bench \ ecore_compose_get_example \ ecore_con_client_example \ @@ -112,6 +116,18 @@ $(ECORE_COMMON_LDADD) ecore_animator_example_SOURCES = ecore_animator_example.c ecore_animator_example_LDADD = $(ECORE_EVAS_COMMON_LDADD) +ecore_buffer_example_SOURCES = ecore_buffer_example.c +ecore_buffer_example_LDADD = $(ECORE_EVAS_COMMON_LDADD) \ + $(top_builddir)/src/lib/ecore_buffer/libecore_buffer.la + +ecore_buffer_consumer_example_SOURCES = ecore_buffer_consumer_example.c +ecore_buffer_consumer_example_LDADD = $(ECORE_EVAS_COMMON_LDADD) \ + $(top_builddir)/src/lib/ecore_buffer/libecore_buffer.la + +ecore_buffer_provider_example_SOURCES = ecore_buffer_provider_example.c +ecore_buffer_provider_example_LDADD = $(ECORE_EVAS_COMMON_LDADD) \ + $(top_builddir)/src/lib/ecore_buffer/libecore_buffer.la + ecore_client_bench_SOURCES = ecore_client_bench.c ecore_client_bench_LDADD = $(ECORE_CON_COMMON_LDADD) @@ -249,6 +265,9 @@ ecore_con_eet_server_example_LDADD = $(ECORE_CON_COMMON_LDADD) SRCS = \ ecore_animator_example.c \ +ecore_buffer_example.c \ +ecore_buffer_consumer_example.c \ +ecore_buffer_provider_example.c \ ecore_audio_custom.c \ ecore_audio_playback.c \ ecore_audio_to_ogg.c \ diff --git a/src/examples/ecore/ecore_buffer_consumer_example.c b/src/examples/ecore/ecore_buffer_consumer_example.c new file mode 100644 index 0000000000..e24a3e2ff1 --- /dev/null +++ b/src/examples/ecore/ecore_buffer_consumer_example.c @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define LOG(f, x...) printf("[CONSUMER|%30.30s|%04d] " f "\n", __func__, __LINE__, ##x) +#else +#define LOG(f, x...) +#endif + +#define WIDTH 720 +#define HEIGHT 960 + +typedef struct _Consumer_Data +{ + Ecore_Buffer_Consumer *consumer; + Ecore_Buffer *buffer; + Ecore_Job *render_job; + struct + { + Evas *e; + Ecore_Evas *ee; + Evas_Object *bg, *img; + } win; +} Consumer_Data; + +const char *name = "ecore_buffer_queue_test"; + +static void +shutdown_all(void) +{ + ecore_buffer_queue_shutdown(); + ecore_buffer_shutdown(); + ecore_evas_shutdown(); + ecore_shutdown(); + eina_shutdown(); +} + +static Eina_Bool +init_all(void) +{ + if (!eina_init()) goto err; + if (!ecore_init()) goto err; + if (!ecore_evas_init()) goto err; + if (!ecore_buffer_init()) goto err; + if (!ecore_buffer_queue_init()) goto err; + + return EINA_TRUE; +err: + shutdown_all(); + return EINA_FALSE; +} + +static void +_cb_render_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Consumer_Data *cd = (Consumer_Data *)data; + + if (cd->buffer) + { + ecore_buffer_consumer_buffer_release(cd->consumer, cd->buffer); + cd->buffer = NULL; + } +} + +static void +_consumer_cb_render_job(void *data) +{ + Consumer_Data *cd = (Consumer_Data *)data; + void *pixel_data; + unsigned int w, h; + + LOG("Startup - Render"); + + if (!(cd->buffer = ecore_buffer_consumer_buffer_dequeue(cd->consumer))) + { + LOG("Failed to dequeue buffer"); + goto end; + } + + LOG("Success to get Compositable Buffer, " + "Drawing it to Consumer's Canvas now... - buffer:%p", cd->buffer); + // Get pixel data and set it to object. + pixel_data = ecore_buffer_data_get(cd->buffer); + ecore_buffer_size_get(cd->buffer, &w, &h); + evas_object_image_data_set(cd->win.img, pixel_data); + evas_object_image_data_update_add(cd->win.img, 0, 0, w, h); + + ecore_job_del(cd->render_job); + cd->render_job = NULL; + +end: + LOG("Done - Render"); +} + +static void +_consumer_render_queue(Consumer_Data *cd) +{ + if (!cd) return; + + LOG("Render Queue"); + + if (!cd->render_job) + cd->render_job = ecore_job_add(_consumer_cb_render_job, cd); +} + +static void +_cb_provider_add(Ecore_Buffer_Consumer *consumer EINA_UNUSED, void *data EINA_UNUSED) +{ + LOG("Connected with Provider"); +} + +static void +_cb_provider_del(Ecore_Buffer_Consumer *consumer EINA_UNUSED, void *data EINA_UNUSED) +{ + LOG("Disconnected with Provider, Shutdown Consumer now."); + ecore_main_loop_quit(); +} + +static void +_cb_buffer_enqueued(Ecore_Buffer_Consumer *consumer EINA_UNUSED, void *data) +{ + Consumer_Data *cd = (Consumer_Data *)data; + + LOG("Buffer Enqueued"); + + _consumer_render_queue(cd); +} + +int +main(void) +{ + Consumer_Data *cd; + Evas_Object *o; + const int queue_size = 3; + + if (!init_all()) + { + LOG("Initializing failed"); + return -1; + } + + cd = (Consumer_Data *)calloc(sizeof(Consumer_Data), 1); + + if (!(cd->consumer = ecore_buffer_consumer_new(name, queue_size, WIDTH, HEIGHT))) + { + LOG("Failed to create consumer"); + goto shutdown; + } + + ecore_buffer_consumer_provider_add_cb_set(cd->consumer, _cb_provider_add, cd); + ecore_buffer_consumer_provider_del_cb_set(cd->consumer, _cb_provider_del, cd); + ecore_buffer_consumer_buffer_enqueued_cb_set(cd->consumer, _cb_buffer_enqueued, cd); + + cd->win.ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + cd->win.e = ecore_evas_get(cd->win.ee); + + o = evas_object_rectangle_add(cd->win.e); + evas_object_move(o, 0, 0); + evas_object_resize(o, WIDTH, HEIGHT); + evas_object_color_set(o, 255, 0, 0, 255); + evas_object_show(o); + cd->win.bg = o; + + o = evas_object_image_add(cd->win.e); + evas_object_image_fill_set(o, 0, 0, WIDTH, HEIGHT); + evas_object_image_size_set(o, WIDTH, HEIGHT); + + evas_object_move(o, 0, 0); + evas_object_resize(o, WIDTH, HEIGHT); + evas_object_show(o); + cd->win.img = o; + + ecore_evas_show(cd->win.ee); + + evas_event_callback_add(cd->win.e, EVAS_CALLBACK_RENDER_POST, _cb_render_post, cd); + + ecore_main_loop_begin(); + +shutdown: + if (cd->win.ee) ecore_evas_free(cd->win.ee); + if (cd->buffer) ecore_buffer_consumer_buffer_release(cd->consumer, cd->buffer); + if (cd->consumer) ecore_buffer_consumer_free(cd->consumer); + if (cd) free(cd); + + shutdown_all(); + return 0; +} diff --git a/src/examples/ecore/ecore_buffer_example.c b/src/examples/ecore/ecore_buffer_example.c new file mode 100644 index 0000000000..7ceeb1710e --- /dev/null +++ b/src/examples/ecore/ecore_buffer_example.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include + +#define WIDTH 720 +#define HEIGHT 960 + +struct _Window +{ + Evas *e; + Ecore_Evas *ee; + Evas_Object *bg, *img; + Ecore_Buffer *buffer; +}; + +struct _Window win; +Eina_List *hdls; + +static void +paint_pixels(void *image, int padding, int width, int height, uint32_t time) +{ + const int halfh = padding + (height - padding * 2) / 2; + const int halfw = padding + (width - padding * 2) / 2; + int ir, or; + uint32_t *pixel = image; + int y; + + /* squared radii thresholds */ + or = (halfw < halfh ? halfw : halfh) - 8; + ir = or - 32; + or *= or; + ir *= ir; + + pixel += padding * width; + for (y = padding; y < height - padding; y++) { + int x; + int y2 = (y - halfh) * (y - halfh); + + pixel += padding; + for (x = padding; x < width - padding; x++) { + uint32_t v; + + /* squared distance from center */ + int r2 = (x - halfw) * (x - halfw) + y2; + + if (r2 < ir) + v = (r2 / 32 + time / 64) * 0x0080401; + else if (r2 < or) + v = (y + time / 32) * 0x0080401; + else + v = (x + time / 16) * 0x0080401; + v &= 0x00ffffff; + v |= 0xff000000; + + *pixel++ = v; + } + + pixel += padding; + } +} + +static void +_cb_post_render(Ecore_Evas *ee EINA_UNUSED) +{ + void *data; + + // Get pixel data and update. + data = ecore_buffer_data_get(win.buffer); + paint_pixels(data, 0, WIDTH, HEIGHT, ecore_loop_time_get() * 1000); + evas_object_image_data_set(win.img, data); + evas_object_image_data_update_add(win.img, 0, 0, WIDTH, HEIGHT); +} + +int +main(void) +{ + Evas_Object *o; + void *data; + + eina_init(); + ecore_init(); + ecore_evas_init(); + ecore_buffer_init(); + + win.ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + win.e = ecore_evas_get(win.ee); + + o = evas_object_rectangle_add(win.e); + evas_object_move(o, 0, 0); + evas_object_resize(o, WIDTH, HEIGHT); + evas_object_color_set(o, 255, 0, 0, 255); + evas_object_show(o); + win.bg = o; + + o = evas_object_image_add(win.e); + evas_object_image_fill_set(o, 0, 0, WIDTH, HEIGHT); + evas_object_image_size_set(o, WIDTH, HEIGHT); + + evas_object_move(o, 0, 0); + evas_object_resize(o, WIDTH, HEIGHT); + evas_object_show(o); + win.img = o; + + // Create buffer and drawing. + win.buffer = ecore_buffer_new("shm", WIDTH, HEIGHT, 0, 0); + data = ecore_buffer_data_get(win.buffer); + paint_pixels(data, 0, WIDTH, HEIGHT, 0); + evas_object_image_data_set(win.img, data); + evas_object_image_data_update_add(win.img, 0, 0, WIDTH, HEIGHT); + + ecore_evas_show(win.ee); + + ecore_evas_callback_post_render_set(win.ee, _cb_post_render); + + ecore_main_loop_begin(); + + ecore_buffer_free(win.buffer); + ecore_buffer_shutdown(); + ecore_evas_shutdown(); + ecore_shutdown(); + eina_shutdown(); + + return 0; +} diff --git a/src/examples/ecore/ecore_buffer_provider_example.c b/src/examples/ecore/ecore_buffer_provider_example.c new file mode 100644 index 0000000000..112854b4dc --- /dev/null +++ b/src/examples/ecore/ecore_buffer_provider_example.c @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define LOG(f, x...) printf("[PROVIDER|%30.30s|%04d] " f "\n", __func__, __LINE__, ##x) +#else +#define LOG(f, x...) +#endif + +typedef struct _Provider_Data +{ + Ecore_Buffer_Provider *provider; + Ecore_Buffer *buffer; + Eina_List *buffer_list; + Ecore_Job *render_job; + Ecore_Idle_Enterer *post_render; + unsigned int w, h; +} Provider_Data; + +const char *name = "ecore_buffer_queue_test"; + +static void _provider_render_queue(Provider_Data *pd); + +static void +shutdown_all(void) +{ + ecore_buffer_queue_shutdown(); + ecore_buffer_shutdown(); + ecore_evas_shutdown(); + ecore_shutdown(); + eina_shutdown(); +} + +static Eina_Bool +init_all(void) +{ + if (!eina_init()) goto err; + if (!ecore_init()) goto err; + if (!ecore_evas_init()) goto err; + if (!ecore_buffer_init()) goto err; + if (!ecore_buffer_queue_init()) goto err; + + return EINA_TRUE; +err: + shutdown_all(); + return EINA_FALSE; +} + +Ecore_Buffer * +_provider_buffer_get(Provider_Data *pd, unsigned int w, unsigned int h, unsigned int format) +{ + Ecore_Buffer *buffer = NULL; + Ecore_Buffer_Return ret; + unsigned int res_w, res_h, res_format; + + LOG("Dequeue"); + ret = ecore_buffer_provider_buffer_acquire(pd->provider, &buffer); + + if (ret == ECORE_BUFFER_RETURN_NEED_ALLOC) + { + buffer = ecore_buffer_new("shm", w, h, format, 0); + pd->buffer_list = eina_list_append(pd->buffer_list, buffer); + LOG("No buffer in Queue, Create Buffer"); + } + else if (ret == ECORE_BUFFER_RETURN_SUCCESS) + { + ecore_buffer_size_get(buffer, &res_w, &res_h); + res_format = ecore_buffer_format_get(buffer); + if ((res_w != w) || (res_h != h) || (res_format != format)) + { + LOG("Need to Reallocate Buffer, Free it First: %p", buffer); + pd->buffer_list = eina_list_remove(pd->buffer_list, buffer); + ecore_buffer_free(buffer); + + buffer = ecore_buffer_new("shm", w, h, format, 0); + pd->buffer_list = eina_list_append(pd->buffer_list, buffer); + LOG("Create Buffer: %p", buffer); + } + } + + return buffer; +} + +static void +paint_pixels(void *image, int padding, int width, int height, uint32_t time) +{ + const int halfh = padding + (height - padding * 2) / 2; + const int halfw = padding + (width - padding * 2) / 2; + int ir, or; + uint32_t *pixel = image; + int y; + + /* squared radii thresholds */ + or = (halfw < halfh ? halfw : halfh) - 8; + ir = or - 32; + or *= or; + ir *= ir; + + pixel += padding * width; + for (y = padding; y < height - padding; y++) { + int x; + int y2 = (y - halfh) * (y - halfh); + + pixel += padding; + for (x = padding; x < width - padding; x++) { + uint32_t v; + + /* squared distance from center */ + int r2 = (x - halfw) * (x - halfw) + y2; + + if (r2 < ir) + v = (r2 / 32 + time / 64) * 0x0080401; + else if (r2 < or) + v = (y + time / 32) * 0x0080401; + else + v = (x + time / 16) * 0x0080401; + v &= 0x00ffffff; + v |= 0xff000000; + + *pixel++ = v; + } + + pixel += padding; + } +} + +static Eina_Bool +_cb_render_post(void *data) +{ + Provider_Data *pd = (Provider_Data *)data; + Ecore_Buffer *next_buffer = NULL; + + LOG("Startup - Post Render"); + + LOG("Submit Buffer - buffer: %p", pd->buffer); + ecore_buffer_provider_buffer_enqueue(pd->provider, pd->buffer); + pd->buffer = NULL; + + next_buffer = _provider_buffer_get(pd, pd->w, pd->h, ECORE_BUFFER_FORMAT_XRGB8888); + if (next_buffer) + { + LOG("Drawable Buffer is Existed, ADD Render job again - buffer:%p", next_buffer); + pd->buffer = next_buffer; + _provider_render_queue(pd); + } + + ecore_idle_enterer_del(pd->post_render); + pd->post_render = NULL; + + LOG("Done - Post Render"); + + return ECORE_CALLBACK_RENEW; +} + +static void +_provider_cb_render_job(void *data) +{ + Provider_Data *pd = (Provider_Data *)data; + + LOG("Startup - Render"); + + if (!pd->buffer) + { + pd->buffer = _provider_buffer_get(pd, + pd->w, pd->h, ECORE_BUFFER_FORMAT_XRGB8888); + } + + if (pd->buffer) + { + void *data; + + LOG("Success to get Drawable Buffer, Drawing now... - buffer:%p", pd->buffer); + // Drawing... + data = ecore_buffer_data_get(pd->buffer); + paint_pixels(data, 0, pd->w, pd->h, ecore_loop_time_get() * 1000); + + if (!pd->post_render) + { + pd->post_render = + ecore_idle_enterer_before_add(_cb_render_post, pd); + } + } + + ecore_job_del(pd->render_job); + pd->render_job = NULL; +} + +static void +_provider_render_queue(Provider_Data *pd) +{ + if (!pd) return; + + LOG("Render Queue"); + + if (!pd->render_job) + pd->render_job = ecore_job_add(_provider_cb_render_job, pd); +} + +static void +_cb_consumer_add(Ecore_Buffer_Provider *provider EINA_UNUSED, int queue_size EINA_UNUSED, int w, int h, void *data) +{ + Provider_Data *pd = (Provider_Data *)data; + + LOG("Connected with Consumer, Now We can use Ecore_Buffer_Queue - queue_size:%d, geo(%dx%d)", + queue_size, w, h); + + pd->w = w; + pd->h = h; + + _provider_render_queue(pd); +} + +static void +_cb_consumer_del(Ecore_Buffer_Provider *provider EINA_UNUSED, void *data EINA_UNUSED) +{ + LOG("Disconnected with Consumer, Shutdown Provider now."); + + ecore_main_loop_quit(); +} + +static void +_cb_buffer_released(Ecore_Buffer_Provider *provider EINA_UNUSED, void *data) +{ + Provider_Data *pd = (Provider_Data *)data; + + LOG("Buffer Enqueued"); + + _provider_render_queue(pd); +} + +int +main(void) +{ + Provider_Data *pd; + + if (!init_all()) + { + LOG("Initializing failed"); + return -1; + } + + pd = (Provider_Data *)calloc(sizeof(Provider_Data), 1); + + if (!(pd->provider = ecore_buffer_provider_new(name))) + { + LOG("Failed to create provider"); + goto shutdown; + } + + ecore_buffer_provider_consumer_add_cb_set(pd->provider, _cb_consumer_add, pd); + ecore_buffer_provider_consumer_del_cb_set(pd->provider, _cb_consumer_del, pd); + ecore_buffer_provider_buffer_released_cb_set(pd->provider, _cb_buffer_released, pd); + + ecore_main_loop_begin(); + +shutdown: + if (pd->buffer_list) + { + Ecore_Buffer *b; + + EINA_LIST_FREE(pd->buffer_list, b) + ecore_buffer_free(b); + } + if (pd->provider) ecore_buffer_provider_free(pd->provider); + if (pd) free(pd); + + shutdown_all(); + return 0; +} diff --git a/src/lib/ecore_buffer/Ecore_Buffer.h b/src/lib/ecore_buffer/Ecore_Buffer.h new file mode 100644 index 0000000000..36c82daad7 --- /dev/null +++ b/src/lib/ecore_buffer/Ecore_Buffer.h @@ -0,0 +1,629 @@ +#ifndef _ECORE_BUFFER_H_ +# define _ECORE_BUFFER_H_ + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_BUFFER_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUFFER_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +/** + * @defgroup Ecore_Buffer_Group Ecore_Buffer - Graphics buffer functions + * @ingroup Ecore + * + * The Ecore Buffer is an abstraction of graphic buffer. + * + * This library also provides simple mechanisms for sharing graphic buffer bet- + * ween processes using wayland socket. Ecore Buffer Queue is for this + * function, and it consists of two main object, + * The Ecore_Buffer_Consumer and the Ecore_Buffer_Provider. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define __ecore_buffer_fourcc_code(a,b,c,d) ((unsigned int)(a) | ((unsigned int)(b) << 8) | \ + ((unsigned int)(c) << 16) | ((unsigned int)(d) << 24)) + +/* color index */ +/** + * @brief Definition for the Ecore_Buffer format C8 ([7:0] C). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_C8 __ecore_buffer_fourcc_code('C', '8', ' ', ' ') +/* 8 bpp RGB */ +/** + * @brief Definition for the Ecore_Buffer format RGB332 ([7:0] R:G:B 3:3:2). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGB332 __ecore_buffer_fourcc_code('R', 'G', 'B', '8') +/** + * @brief Definition for the Ecore_Buffer format RGB233 ([7:0] B:G:R 2:3:3). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGR233 __ecore_buffer_fourcc_code('B', 'G', 'R', '8') +/* 16 bpp RGB */ +/** + * @brief Definition for the Ecore_Buffer format XRGB4444 ([15:0] x:R:G:B 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XRGB4444 __ecore_buffer_fourcc_code('X', 'R', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format XBRG4444 ([15:0] x:B:G:R 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XBGR4444 __ecore_buffer_fourcc_code('X', 'B', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format RGBX4444 ([15:0] R:G:B:x 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBX4444 __ecore_buffer_fourcc_code('R', 'X', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format BGRX4444 ([15:0] B:G:R:x 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRX4444 __ecore_buffer_fourcc_code('B', 'X', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format ARGB4444 ([15:0] A:R:G:B 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ARGB4444 __ecore_buffer_fourcc_code('A', 'R', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format ABGR4444 ([15:0] A:B:G:R 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ABGR4444 __ecore_buffer_fourcc_code('A', 'B', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format RGBA4444 ([15:0] R:G:B:A 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBA4444 __ecore_buffer_fourcc_code('R', 'A', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format BGRA4444 ([15:0] B:G:R:A 4:4:4:4 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRA4444 __ecore_buffer_fourcc_code('B', 'A', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format XRGB1555 ([15:0] x:R:G:B 1:5:5:5 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XRGB1555 __ecore_buffer_fourcc_code('X', 'R', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format XBGR1555 ([15:0] x:B:G:R 1:5:5:5 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XBGR1555 __ecore_buffer_fourcc_code('X', 'B', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format RGBX5551 ([15:0] R:G:B:x 5:5:5:1 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBX5551 __ecore_buffer_fourcc_code('R', 'X', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format BGRX5551 ([15:0] B:G:R:x 5:5:5:1 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRX5551 __ecore_buffer_fourcc_code('B', 'X', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format ARGB1555 ([15:0] A:R:G:B 1:5:5:5 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ARGB1555 __ecore_buffer_fourcc_code('A', 'R', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format ABGR1555 ([15:0] A:B:G:R 1:5:5:5 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ABGR1555 __ecore_buffer_fourcc_code('A', 'B', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format RGBA5551 ([15:0] R:G:B:A 5:5:5:1 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBA5551 __ecore_buffer_fourcc_code('R', 'A', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format BGRA5551 ([15:0] B:G:R:A 5:5:5:1 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRA5551 __ecore_buffer_fourcc_code('B', 'A', '1', '5') +/** + * @brief Definition for the Ecore_Buffer format RGB565 ([15:0] R:G:B 5:6:5 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGB565 __ecore_buffer_fourcc_code('R', 'G', '1', '6') +/** + * @brief Definition for the Ecore_Buffer format BGR565 ([15:0] B:G:R 5:6:5 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGR565 __ecore_buffer_fourcc_code('B', 'G', '1', '6') +/* 24 bpp RGB */ +/** + * @brief Definition for the Ecore_Buffer format RGB888 ([23:0] R:G:B little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGB888 __ecore_buffer_fourcc_code('R', 'G', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format BGR888 ([23:0] B:G:R little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGR888 __ecore_buffer_fourcc_code('B', 'G', '2', '4') +/* 32 bpp RGB */ +/** + * @brief Definition for the Ecore_Buffer format XRGB8888 ([31:0] x:R:G:B 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XRGB8888 __ecore_buffer_fourcc_code('X', 'R', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format XBGR8888 ([31:0] x:B:G:R 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XBGR8888 __ecore_buffer_fourcc_code('X', 'B', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format RGBX8888 ([31:0] R:G:B:x 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBX8888 __ecore_buffer_fourcc_code('R', 'X', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format BGRX8888 ([31:0] B:G:R:x 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRX8888 __ecore_buffer_fourcc_code('B', 'X', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format ARGB8888 ([31:0] A:R:G:B 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ARGB8888 __ecore_buffer_fourcc_code('A', 'R', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format ABGR8888 ([31:0] [31:0] A:B:G:R 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ABGR8888 __ecore_buffer_fourcc_code('A', 'B', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format RGBA8888 ([31:0] R:G:B:A 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBA8888 __ecore_buffer_fourcc_code('R', 'A', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format BGRA8888 ([31:0] B:G:R:A 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRA8888 __ecore_buffer_fourcc_code('B', 'A', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format XRGB2101010 ([31:0] x:R:G:B 2:10:10:10 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XRGB2101010 __ecore_buffer_fourcc_code('X', 'R', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format XBGR2101010 ([31:0] x:B:G:R 2:10:10:10 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_XBGR2101010 __ecore_buffer_fourcc_code('X', 'B', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format RGBX1010102 ([31:0] R:G:B:x 10:10:10:2 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBX1010102 __ecore_buffer_fourcc_code('R', 'X', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format BGRX1010102 ([31:0] B:G:R:x 10:10:10:2 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRX1010102 __ecore_buffer_fourcc_code('B', 'X', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format ARGB2101010 ([31:0] A:R:G:B 2:10:10:10 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ARGB2101010 __ecore_buffer_fourcc_code('A', 'R', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format ABGR2101010 ([31:0] A:B:G:R 2:10:10:10 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_ABGR2101010 __ecore_buffer_fourcc_code('A', 'B', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format RGBA1010102 ([31:0] R:G:B:A 10:10:10:2 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_RGBA1010102 __ecore_buffer_fourcc_code('R', 'A', '3', '0') +/** + * @brief Definition for the Ecore_Buffer format BGRA1010102 ([31:0] B:G:R:A 10:10:10:2 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_BGRA1010102 __ecore_buffer_fourcc_code('B', 'A', '3', '0') +/* packed YCbCr */ +/** + * @brief Definition for the Ecore_Buffer format YUYV ([31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YUYV __ecore_buffer_fourcc_code('Y', 'U', 'Y', 'V') +/** + * @brief Definition for the Ecore_Buffer format YVYU ([31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YVYU __ecore_buffer_fourcc_code('Y', 'V', 'Y', 'U') +/** + * @brief Definition for the Ecore_Buffer format UYVY ([31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_UYVY __ecore_buffer_fourcc_code('U', 'Y', 'V', 'Y') +/** + * @brief Definition for the Ecore_Buffer format VYUY ([31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_VYUY __ecore_buffer_fourcc_code('V', 'Y', 'U', 'Y') +/** + * @brief Definition for the Ecore_Buffer format AYUV ([31:0] A:Y:Cb:Cr 8:8:8:8 little endian). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_AYUV __ecore_buffer_fourcc_code('A', 'Y', 'U', 'V') +/* + * 2 plane YCbCr + * index 0 = Y plane, [7:0] Y + * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian + * or + * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian + */ +/** + * @brief Definition for the Ecore_Buffer format NV12 (2x2 subsampled Cr:Cb plane). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_NV12 __ecore_buffer_fourcc_code('N', 'V', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format NV21 (2x2 subsampled Cb:Cr plane). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_NV21 __ecore_buffer_fourcc_code('N', 'V', '2', '1') +/** + * @brief Definition for the Ecore_Buffer format NV16 (2x1 subsampled Cr:Cb plane). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_NV16 __ecore_buffer_fourcc_code('N', 'V', '1', '6') +/** + * @brief Definition for the Ecore_Buffer format NV61 (2x1 subsampled Cb:Cr plane). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_NV61 __ecore_buffer_fourcc_code('N', 'V', '6', '1') +/* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + * index 1: Cb plane, [7:0] Cb + * index 2: Cr plane, [7:0] Cr + * or + * index 1: Cr plane, [7:0] Cr + * index 2: Cb plane, [7:0] Cb + */ +/** + * @brief Definition for the Ecore_Buffer format YUV410 (4x4 subsampled Cb (1) and Cr (2) planes). + */ +#define ECORE_BUFFER_FORMAT_YUV410 __ecore_buffer_fourcc_code('Y', 'U', 'V', '9') +/** + * @brief Definition for the Ecore_Buffer format YVU410 (4x4 subsampled Cr (1) and Cb (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YVU410 __ecore_buffer_fourcc_code('Y', 'V', 'U', '9') +/** + * @brief Definition for the Ecore_Buffer format YUV411 (4x1 subsampled Cb (1) and Cr (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YUV411 __ecore_buffer_fourcc_code('Y', 'U', '1', '1') +/** + * @brief Definition for the Ecore_Buffer format YVU411 (4x1 subsampled Cr (1) and Cb (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YVU411 __ecore_buffer_fourcc_code('Y', 'V', '1', '1') +/** + * @brief Definition for the Ecore_Buffer format YUV420 (2x2 subsampled Cb (1) and Cr (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YUV420 __ecore_buffer_fourcc_code('Y', 'U', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format YVU420 (2x2 subsampled Cr (1) and Cb (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YVU420 __ecore_buffer_fourcc_code('Y', 'V', '1', '2') +/** + * @brief Definition for the Ecore_Buffer format YUV422 (2x1 subsampled Cb (1) and Cr (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YUV422 __ecore_buffer_fourcc_code('Y', 'U', '1', '6') +/** + * @brief Definition for the Ecore_Buffer format YVU422 (2x1 subsampled Cr (1) and Cb (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YVU422 __ecore_buffer_fourcc_code('Y', 'V', '1', '6') +/** + * @brief Definition for the Ecore_Buffer format YUV444 (non-subsampled Cb (1) and Cr (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YUV444 __ecore_buffer_fourcc_code('Y', 'U', '2', '4') +/** + * @brief Definition for the Ecore_Buffer format YVU444 (non-subsampled Cr (1) and Cb (2) planes). + * @since 1.15 + */ +#define ECORE_BUFFER_FORMAT_YVU444 __ecore_buffer_fourcc_code('Y', 'V', '2', '4') + +/** + * @defgroup Ecore_Buffer_Lib_Group Ecore Buffer Library Functions + * @ingroup Ecore_Buffer_Group + * + * Utility functions that set up and shut down the Ecore Buffer library. + * This group of functions is applied to an Ecore_Buffer object. + * + * @{ + */ + +/** + * @typedef Ecore_Buffer + * An object representing a graphic buffer. + * @since 1.15 + */ +typedef struct _Ecore_Buffer Ecore_Buffer; +/** + * @typedef Ecore_Buffer_Backend + * The interfaces for backend of buffer. + * @since 1.15 + */ +typedef struct _Ecore_Buffer_Backend Ecore_Buffer_Backend; +/** + * @typedef Ecore_Export_Type + * Types for export buffer. + * @since 1.15 + */ +typedef enum _Ecore_Export_Type Ecore_Export_Type; +/** + * @typedef Ecore_Buffer_Format + * The format of Ecore_Buffer. + * @since 1.15 + */ +typedef unsigned int Ecore_Buffer_Format; +/** + * @typedef Ecore_Buffer_Pixmap + * An Id of Pixmap. + * @since 1.15 + */ +typedef unsigned long Ecore_Pixmap; +/** + * @typedef Ecore_Buffer_Module_Data + * The data of module. + * @since 1.15 + */ +typedef void* Ecore_Buffer_Module_Data; +/** + * @typedef Ecore_Buffer_Data + * The data of Ecore_Buffer. + * @since 1.15 + */ +typedef void* Ecore_Buffer_Data; +/** + * @typedef Ecore_Buffer_Cb + * Called whenever Ecore_Buffer is freed. + * @since 1.15 + */ +typedef void (*Ecore_Buffer_Cb)(Ecore_Buffer* buf, void* data); + +/** + * @enum _Ecore_Export_Type + * Types for export buffer. + * @since 1.15 + */ +enum _Ecore_Export_Type +{ + EXPORT_TYPE_INVALID, + EXPORT_TYPE_ID, + EXPORT_TYPE_FD +}; + +/** + * @struct _Ecore_Buffer_Backend + * @brief Structure used when initializing Ecore Buffer Backend. This structure + * is mainly used by modules implementing the Ecore Buffer Backend interface. + * @since 1.15 + */ +struct _Ecore_Buffer_Backend +{ + const char *name; /**< The name of backend */ + + Ecore_Buffer_Module_Data (*init)(const char *context, const char *options); /**< Initialize the backend */ + void (*shutdown)(Ecore_Buffer_Module_Data bmdata); /**< Shut down the backend */ + Ecore_Buffer_Data (*buffer_alloc)(Ecore_Buffer_Module_Data bmdata, + int width, int height, + Ecore_Buffer_Format format, + unsigned int flags); /**< Newly allocate memory for buffer */ + void (*buffer_free)(Ecore_Buffer_Module_Data bmdata, + Ecore_Buffer_Data bdata); /**< Free allocated memory */ + Ecore_Export_Type (*buffer_export)(Ecore_Buffer_Module_Data bmdata, + Ecore_Buffer_Data bdata, int *id); /**< Get the id or fd of Ecore_Buffer for exporting it */ + Ecore_Buffer_Data (*buffer_import)(Ecore_Buffer_Module_Data bmdata, + int w, int h, + Ecore_Buffer_Format format, + Ecore_Export_Type type, + int export_id, + unsigned int flags); /**< Import and create Ecore_Buffer from id or fd */ + void *(*data_get)(Ecore_Buffer_Module_Data bmdata, + Ecore_Buffer_Data bdata); + Ecore_Pixmap (*pixmap_get)(Ecore_Buffer_Module_Data bmdata, + Ecore_Buffer_Data bdata); /**< Get the pixmap handle */ + void *(*tbm_surface_get)(Ecore_Buffer_Module_Data bmdata, + Ecore_Buffer_Data bdata); /**< Get the tbm_surface_h handle */ +}; + +/** + * @brief Initialize the Ecore_Buffer system. + * + * @since 1.15 + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ecore_buffer_shutdown() + */ +EAPI Eina_Bool ecore_buffer_init(void); +/** + * @brief Shut down the Ecore_Buffer system. + * + * @since 1.15 + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ecore_buffer_init() + */ +EAPI Eina_Bool ecore_buffer_shutdown(void); +/** + * @brief Registers the given buffer backend. + * + * @since 1.15 + * + * @param[in] be The backend + * + * @return @c EINA_TRUE if backend has been correctly registered, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_buffer_register(Ecore_Buffer_Backend *be); +/** + * @brief Unregisters the given buffer backend. + * + * @since 1.15 + * + * @param[in] be The backend + */ +EAPI void ecore_buffer_unregister(Ecore_Buffer_Backend *be); +/** + * @brief Creates a new Ecore_Buffer given type + * + * @since 1.15 + * + * @param[in] engine the name of backend + * @param[in] width width for Ecore_Buffer + * @param[in] height height for Ecore_Buffer + * @param[in] format format for Ecore_Buffer + * @param[in] flags flags for Ecore_Buffer + * + * @return Newly allocated Ecore_Buffer instance, NULL otherwise. + */ +EAPI Ecore_Buffer *ecore_buffer_new(const char *engine, unsigned int width, unsigned int height, Ecore_Buffer_Format format, unsigned int flags); +/** + * @brief Free the given Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer to free + */ +EAPI void ecore_buffer_free(Ecore_Buffer *buf); +/** + * @brief Set a callback for Ecore_Buffer free events. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer, causing + * @p func to be called whenever @p buf is freed. + * + * @see ecore_buffer_free_callback_remove() + */ +EAPI void ecore_buffer_free_callback_add(Ecore_Buffer *buf, Ecore_Buffer_Cb func, void *data); +/** + * @brief Remove a callback for Ecore_Buffer free events. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer to remove callbacks on + * @param[in] func The function to remove + * @param[in] data A pointer to the user data to remove + * + * @see ecore_buffer_free_callback_add() + */ +EAPI void ecore_buffer_free_callback_remove(Ecore_Buffer *buf, Ecore_Buffer_Cb func, void *data); +/** + * @brief Get a pointer to the raw data of the given Ecore_Buffer. + * + * @param[in] buf The Ecore_Buffer. + * + * @return The pointer of raw data. + */ +EAPI void *ecore_buffer_data_get(Ecore_Buffer *buf); +/** + * @brief Return the Pixmap of given Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer + * + * @return The Pixmap instance, 0 otherwise. + */ +EAPI Ecore_Pixmap ecore_buffer_pixmap_get(Ecore_Buffer *buf); +/** + * @brief Return the tbm surface handle of given Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer + * + * @return The tbm surface handle, NULL otherwise. + * + * The tbm surface handle will be used for the API of libtbm. + * The API is described in tbm_surface.h in libtbm. + */ +EAPI void *ecore_buffer_tbm_surface_get(Ecore_Buffer *buf); +/** + * @brief Return size of given Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer + * @param[out] width where to return the width value. May be @c NULL. + * @param[out] height where to return the height value. May be @c NULL. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_buffer_size_get(Ecore_Buffer *buf, unsigned int *width, unsigned int *height); +/** + * @brief Return format of given Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer + * + * @return The format of given Ecore_Buffer. + * + * return value can be one of those pre-defined value such as ECORE_BUFFER_FORMAT_XRGB8888. + */ +EAPI Ecore_Buffer_Format ecore_buffer_format_get(Ecore_Buffer *buf); +/** + * @brief Return flags of given Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] buf The Ecore_Buffer + * + * @return The flags of given Ecore_Buffer. + * + * NOTE: Not Defined yet. + */ +EAPI unsigned int ecore_buffer_flags_get(Ecore_Buffer *buf); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_buffer/Ecore_Buffer_Queue.h b/src/lib/ecore_buffer/Ecore_Buffer_Queue.h new file mode 100644 index 0000000000..81dad17976 --- /dev/null +++ b/src/lib/ecore_buffer/Ecore_Buffer_Queue.h @@ -0,0 +1,449 @@ +#ifndef _ECORE_BUFFER_QUEUE_H_ +#define _ECORE_BUFFER_QUEUE_H_ + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_BUFFER_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUFFER_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "Ecore_Buffer.h" + +/** + * @defgroup Ecore_Buffer_Queue_Group Ecore Buffer Queue functions + * @ingroup Ecore_Buffer_Group + * + * Ecore Buffer Queue is a queue which conntects processes for sharing + * Ecore_Buffer. + * one process (related object is Ecore_Buffer_Provider) has rear terminal + * position of Ecore_Buffer Queue which can enqueue the Ecore_Buffer, + * and the other process (related object is Ecore_Buffer_Consumer) has front + * terminal position of Ecore_Buffer_Queue which can dequeue the Ecore_Buffer. + */ + +/** + * @defgroup Ecore_Buffer_Provider_Group Ecore Buffer Provider functions + * @ingroup Ecore_Buffer_Queue_Group + * + * This group of functions is applied to an Ecore_Buffer_Provider object. + * Ecore_Buffer_Provider provides Ecore_Buffer to Ecore_Buffer_Consumer(usally + * different process or thread from Ecore_Buffer_Provider). + * Ecore_Buffer_Provider should creates Ecore_Buffer as a provider. + */ + +/** + * @defgroup Ecore_Buffer_Consumer_Group Ecore Buffer Consumer functions + * @ingroup Ecore_Buffer_Queue_Group + * + * This group of functions is applied to an Ecore_Buffer_Consumer object. + * Ecore_Buffer_Consumer receives Ecore_Buffer enqueued by Ecore_Buffer_Provider. + * Consumer must release Ecore_Buffer when it's no longer used. + * Thus, the Ecore_Buffer_Provider is now free to re-use or destroy Ecore_Buffer. + */ + +/** + * @typedef Ecore_Buffer_Return + * @enum _Ecore_Buffer_Return + * types for an buffer queue state on provider side. + * @ingroup Ecore_Buffer_Provider_Group + * @see ecore_buffer_provider_buffer_acquire() + * @see ecore_buffer_provider_buffer_acquirable_check() + */ +typedef enum _Ecore_Buffer_Return +{ + ECORE_BUFFER_RETURN_ERROR, /**< on error @since 1.15 */ + ECORE_BUFFER_RETURN_SUCCESS, /**< success to dequeue a buffer @since 1.15 */ + ECORE_BUFFER_RETURN_EMPTY, /**< Empty queue @since 1.15 */ + ECORE_BUFFER_RETURN_NOT_EMPTY, /**< Not empty queue @since 1.15 */ + ECORE_BUFFER_RETURN_NEED_ALLOC, /**< need to create Ecore_Buffer @since 1.15 */ +} Ecore_Buffer_Return; +/** + * @typedef Ecore_Buffer_Consumer + * An object representing a consumer of Ecore_Buffer. + * + * @since 1.15 + * + * @ingroup Ecore_Buffer_Consumer_Group + */ +typedef struct _Ecore_Buffer_Consumer Ecore_Buffer_Consumer; +/** + * @typedef Ecore_Buffer_Provider + * An object representing a provider of Ecore_Buffer. + * + * @since 1.15 + * + * @ingroup Ecore_Buffer_Provider_Group + */ +typedef struct _Ecore_Buffer_Provider Ecore_Buffer_Provider; +/** + * @typedef Ecore_Buffer_Consumer_Provider_Add_Cb + * + * @brief Called whenever a Ecore_Buffer_Provider connected. + * + * @since 1.15 + * + * @see ecore_buffer_consumer_provider_add_cb_set() + * @ingroup Ecore_Buffer_Consumer_Group + */ +typedef void (*Ecore_Buffer_Consumer_Provider_Add_Cb) (Ecore_Buffer_Consumer *consumer, void *data); +/** + * @typedef Ecore_Buffer_Consumer_Provider_Del_Cb + * + * @brief Called whenever a Ecore_Buffer_Provider disonnected. + * + * @since 1.15 + * + * @see ecore_buffer_consumer_provider_del_cb_set() + * @ingroup Ecore_Buffer_Consumer_Group + */ +typedef void (*Ecore_Buffer_Consumer_Provider_Del_Cb) (Ecore_Buffer_Consumer *consumer, void *data); +/** + * @typedef Ecore_Buffer_Consumer_Enqueue_Cb + * + * @brief Called whenever a Ecore_Buffer enqueued in buffer queue. + * + * @since 1.15 + * + * @see ecore_buffer_consumer_buffer_enqueued_cb_set() + * @ingroup Ecore_Buffer_Consumer_Group + */ +typedef void (*Ecore_Buffer_Consumer_Enqueue_Cb) (Ecore_Buffer_Consumer *consumer, void *data); +/** + * @typedef Ecore_Buffer_Provider_Consumer_Add_Cb + * + * @brief Called whenever a Ecore_Buffer_Consumer connected. + * + * @since 1.15 + * + * @see ecore_buffer_provider_consumer_add_cb_set() + * @ingroup Ecore_Buffer_Provider_Group + */ +typedef void (*Ecore_Buffer_Provider_Consumer_Add_Cb) (Ecore_Buffer_Provider *provider, int queue_size, int w, int h, void *data); +/** + * @typedef Ecore_Buffer_Provider_Consumer_Del_Cb + * + * @brief Called whenever a Ecore_Buffer_Consumer disconnected. + * + * @since 1.15 + * + * @see ecore_buffer_provider_consumer_del_cb_set() + * @ingroup Ecore_Buffer_Provider_Group + */ +typedef void (*Ecore_Buffer_Provider_Consumer_Del_Cb) (Ecore_Buffer_Provider *provider, void *data); +/** + * @typedef Ecore_Buffer_Provider_Enqueue_Cb + * + * @brief Called whenever a Ecore_Buffer is released. + * + * @since 1.15 + * + * @see ecore_buffer_provider_buffer_released_cb_set() + * @ingroup Ecore_Buffer_Provider_Group + */ +typedef void (*Ecore_Buffer_Provider_Enqueue_Cb) (Ecore_Buffer_Provider *provider, void *data); + +/** + * @addtogroup Ecore_Buffer_Queue_Group + * @{ + */ + +/** + * @brief Init the Ecore_Buffer_Queue system. + * + * @since 1.15 + * + * @return How many times the lib has been initialized, 0 indicates failure. + * + * Set up the connection of Buffer Queue deamon, and Init Ecore_Buffer_Queue libraries. + * + * @see ecore_buffer_queue_shutdown() + */ +EAPI int ecore_buffer_queue_init(void); +/** + * @brief Shut down the Ecore_Buffer_Queue system. + * + * @since 1.15 + * + * this closes the connection of Buffer Queue deamon, and Shut down Ecore_Buffer_Queue libraries. + * + * @see ecore_buffer_queue_init() + */ +EAPI int ecore_buffer_queue_shutdown(void); + +/** + * @} + */ + +/** + * @addtogroup Ecore_Buffer_Consumer_Group + * @{ + */ + +/** + * @brief Creates a new Buffer Consumer based on name and common parameters. + * + * @since 1.15 + * + * @param[in] name the name of Buffer_Queue, this is needed by Consumer and Provider to connect each other. + * @param[in] queue_size size of Queue (If you pass this 0, then default size two(2) is appied) + * @param[in] w width of buffer recommeneded to provider. + * @param[in] h height of buffer recommended to provider. + * + * @return Ecore_Buffer_Consumer instance or @c NULL if creation failed. + */ +EAPI Ecore_Buffer_Consumer *ecore_buffer_consumer_new(const char *name, int32_t queue_size, int32_t w, int32_t h); +/** + * @brief Free an Ecore_Buffer_Consumer + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to free + * + * This frees up any memory used by the Ecore_Buffer_Consumer. + */ +EAPI void ecore_buffer_consumer_free(Ecore_Buffer_Consumer *consumer); +/** + * @brief Return the latest Ecore_Buffer submitted by provider. + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to request for buffer + * + * @return Ecore_Buffer handle or NULL if acquirement failed. + * + * @see ecore_buffer_consumer_buffer_release() + * + * Consumer can store Ecore_Buffer submitted by Provider as much as size of queue + * which is passed as a argument of ecore_buffer_consumer_new(). + */ +EAPI Ecore_Buffer *ecore_buffer_consumer_buffer_dequeue(Ecore_Buffer_Consumer *consumer); +/** + * @brief Release the acquired Ecore_Buffer. + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to request release buffer + * @param[in] buffer The Ecore_Buffer to release + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ecore_buffer_consumer_buffer_dequeue() + * + * Consumer should release the Ecore_Buffer after acquiring and using it. + * By doing release, Ecore_Buffer will be used by provider again, + * or freed internally if Ecore_Buffer is not necessary anymore. + * If not, the resource of Ecore_Buffer is continually owned by consumer until released. + */ +EAPI Eina_Bool ecore_buffer_consumer_buffer_release(Ecore_Buffer_Consumer *consumer, Ecore_Buffer *buffer); +/** + * @brief Check if Queue of Ecore_Buffer is empty. + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to query + * + * @return @c EINA_TRUE means queue is empty, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_buffer_consumer_queue_is_empty(Ecore_Buffer_Consumer *consumer); +/** + * @brief Set a callback for provider connection events. + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer_Consumer, causing + * @p func to be called whenever @p consumer is connected with provider. + */ +EAPI void ecore_buffer_consumer_provider_add_cb_set(Ecore_Buffer_Consumer *consumer, Ecore_Buffer_Consumer_Provider_Add_Cb func, void *data); +/** + * @brief Set a callback for provider disconnection events. + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer_Consumer, causing + * @p func to be called whenever @p consumer is disconnected with provider. + */ +EAPI void ecore_buffer_consumer_provider_del_cb_set(Ecore_Buffer_Consumer *consumer, Ecore_Buffer_Consumer_Provider_Del_Cb func, void *data); +/** + * @brief Set a callback for enqueued buffer events. + * + * @since 1.15 + * + * @param[in] consumer The Ecore_Buffer_Consumer to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer_Consumer, causing + * @p func to be called whenever @p consumer has received buffer submitted from provider. + * + * You may success acuiqre Ecore_Buffer after this callback called. + */ +EAPI void ecore_buffer_consumer_buffer_enqueued_cb_set(Ecore_Buffer_Consumer *consumer, Ecore_Buffer_Consumer_Enqueue_Cb func, void *data); + +/** + * @} + */ + +/** + * @addtogroup Ecore_Buffer_Provider_Group + * @{ + */ + +/** + * @brief Creates a new Buffer Provider based on name. + * + * @since 1.15 + * + * @param[in] name the name of Buffer_Queue. + * + * @return Ecore_Buffer_Provider instance or @c NULL if creation failed. + */ +EAPI Ecore_Buffer_Provider *ecore_buffer_provider_new(const char *name); +/** + * @brief Free an Ecore_Buffer_Provider + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider to free + * + * This frees up any memory used by the Ecore_Buffer_Provider. + */ +EAPI void ecore_buffer_provider_free(Ecore_Buffer_Provider *provider); +/** + * @brief Return the Ecore_Buffer released by consumer or State of Queue. + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider to request for buffer + * @param[out] ret_buf A Pointer to the Ecore_Buffer + * + * @return The enumeration of Ecore_Buffer_Return to indicate result of Dequeueing. + * + * This function gives you drawable buffer and inform you the state of Queue. + * Each return value of enumeration has meaning as below. + * @li ECORE_BUFFER_RETURN_ERROR, means error occured. + * @li ECORE_BUFFER_RETURN_SUCCESS, means success to dequeue, therefore ret_buf is valid. + * @li ECORE_BUFFER_RETURN_EMPTY, means queue is empty, not available slot in Queue. + * in other words, there is no free drawable buffer in Queue. + * @li ECORE_BUFFER_RETURN_NEED_ALLOC, means that there is available slot, but not allocated. + * so, You may create new Ecore_Buffer, and then just enqueue the Ecore_Buffer. + * + * @see ecore_buffer_new(), ecore_buffer_provider_buffer_enqueue() + */ +EAPI Ecore_Buffer_Return ecore_buffer_provider_buffer_acquire(Ecore_Buffer_Provider *provider, Ecore_Buffer **ret_buf); +/** + * @brief Submit the Ecore_Buffer to Consumer to request compositing. + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider connected with consumer. + * @param[in] buffer The Ecore_Buffer to submit + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function allow you to submit the Ecore_Buffer to consumer to request compositing. + * And this will be success, in case only you submit dequeued Ecore_Buffer, + * and new Ecore_Buffer after received return value of ECORE_BUFFER_RETURN_NEED_ALLOC by ecore_buffer_provider_buffer_acquire(). + * + * @see ecore_buffer_new(), ecore_buffer_provider_buffer_dequeue() + */ +EAPI Eina_Bool ecore_buffer_provider_buffer_enqueue(Ecore_Buffer_Provider *provider, Ecore_Buffer *buffer); +/** + * @brief Check if state of queue. + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider to query + * + * @li ECORE_BUFFER_RETURN_NOT_EMPTY, means there is a dequeueable Ecore_Buffer at least one. + * @li ECORE_BUFFER_RETURN_EMPTY, means queue is empty, not available slot in Queue. + * in other words, there is no free drawable buffer in Queue. + * @li ECORE_BUFFER_RETURN_NEED_ALLOC, means that there is available slot, but not allocated. + * so, You may create new Ecore_Buffer, and then just enqueue the Ecore_Buffer. + * + * @return @c EINA_TRUE means queue is empty, @c EINA_FALSE otherwise. + */ +EAPI Ecore_Buffer_Return ecore_buffer_provider_buffer_acquirable_check(Ecore_Buffer_Provider *provider); +/** + * @brief Set a callback for consumer connection events. + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer_Provider, causing + * @p func to be called whenever @p provider is connected with consumer. + */ +EAPI void ecore_buffer_provider_consumer_add_cb_set(Ecore_Buffer_Provider *provider, Ecore_Buffer_Provider_Consumer_Add_Cb func, void *data); +/** + * @brief Set a callback for consumer disconnection events. + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer_Provider, causing + * @p func to be called whenever @p provider is disconnected with consumer. + */ +EAPI void ecore_buffer_provider_consumer_del_cb_set(Ecore_Buffer_Provider *provider, Ecore_Buffer_Provider_Consumer_Del_Cb func, void *data); +/** + * @brief Set a callback for released buffer events. + * + * @since 1.15 + * + * @param[in] provider The Ecore_Buffer_Provider to set callbacks on + * @param[in] func The function to call + * @param[in] data A pointer to the user data to store. + * + * A call to this function will set a callback on an Ecore_Buffer_Provider, causing + * @p func to be called whenever @p provider has received Ecore_Buffer released from provider. + * + * You may success dequeue the Ecore_Buffer after this callback called. + */ +EAPI void ecore_buffer_provider_buffer_released_cb_set(Ecore_Buffer_Provider *provider, Ecore_Buffer_Provider_Enqueue_Cb func, void *data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ECORE_BUFFER_QUEUE_H_ */ diff --git a/src/lib/ecore_buffer/bq_mgr_protocol.c b/src/lib/ecore_buffer/bq_mgr_protocol.c new file mode 100644 index 0000000000..fe8b98c9bc --- /dev/null +++ b/src/lib/ecore_buffer/bq_mgr_protocol.c @@ -0,0 +1,131 @@ +#include +#include +#include "wayland-util.h" + +extern const struct wl_interface bq_buffer_interface; +extern const struct wl_interface bq_consumer_interface; +extern const struct wl_interface bq_provider_interface; + +static const struct wl_interface *types[] = { + NULL, + NULL, + NULL, + &bq_consumer_interface, + NULL, + NULL, + NULL, + NULL, + &bq_provider_interface, + NULL, + &bq_buffer_interface, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + &bq_buffer_interface, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &bq_buffer_interface, + &bq_buffer_interface, + NULL, + &bq_buffer_interface, + NULL, +}; + +static const struct wl_message bq_mgr_requests[] = { + { "create_consumer", "nsiii", types + 3 }, + { "create_provider", "ns", types + 8 }, +}; + +WL_EXPORT const struct wl_interface bq_mgr_interface = { + "bq_mgr", 1, + 2, bq_mgr_requests, + 0, NULL, +}; + +static const struct wl_message bq_consumer_requests[] = { + { "release_buffer", "o", types + 10 }, +}; + +static const struct wl_message bq_consumer_events[] = { + { "connected", "", types + 0 }, + { "disconnected", "", types + 0 }, + { "buffer_attached", "nsiiiu", types + 11 }, + { "set_buffer_id", "oiiiiiii", types + 17 }, + { "set_buffer_fd", "ohiiiiii", types + 25 }, + { "buffer_detached", "o", types + 33 }, + { "add_buffer", "ou", types + 34 }, +}; + +WL_EXPORT const struct wl_interface bq_consumer_interface = { + "bq_consumer", 1, + 1, bq_consumer_requests, + 7, bq_consumer_events, +}; + +static const struct wl_message bq_provider_requests[] = { + { "attach_buffer", "nsiiiu", types + 36 }, + { "set_buffer_id", "oiiiiiii", types + 42 }, + { "set_buffer_fd", "ohiiiiii", types + 50 }, + { "detach_buffer", "o", types + 58 }, + { "enqueue_buffer", "ou", types + 59 }, +}; + +static const struct wl_message bq_provider_events[] = { + { "connected", "iii", types + 0 }, + { "disconnected", "", types + 0 }, + { "add_buffer", "ou", types + 61 }, +}; + +WL_EXPORT const struct wl_interface bq_provider_interface = { + "bq_provider", 1, + 5, bq_provider_requests, + 3, bq_provider_events, +}; + +WL_EXPORT const struct wl_interface bq_buffer_interface = { + "bq_buffer", 1, + 0, NULL, + 0, NULL, +}; + diff --git a/src/lib/ecore_buffer/bq_mgr_protocol.h b/src/lib/ecore_buffer/bq_mgr_protocol.h new file mode 100644 index 0000000000..7cf9ad9380 --- /dev/null +++ b/src/lib/ecore_buffer/bq_mgr_protocol.h @@ -0,0 +1,329 @@ +#ifndef BQ_MGR_CLIENT_PROTOCOL_H +#define BQ_MGR_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct bq_mgr; +struct bq_consumer; +struct bq_provider; +struct bq_buffer; + +extern const struct wl_interface bq_mgr_interface; +extern const struct wl_interface bq_consumer_interface; +extern const struct wl_interface bq_provider_interface; +extern const struct wl_interface bq_buffer_interface; + +#ifndef BQ_MGR_ERROR_ENUM +#define BQ_MGR_ERROR_ENUM +enum bq_mgr_error { + BQ_MGR_ERROR_INVALID_PERMISSION = 0, + BQ_MGR_ERROR_INVALID_NAME = 1, + BQ_MGR_ERROR_ALREADY_USED = 2, +}; +#endif /* BQ_MGR_ERROR_ENUM */ + +#define BQ_MGR_CREATE_CONSUMER 0 +#define BQ_MGR_CREATE_PROVIDER 1 + +static inline void +bq_mgr_set_user_data(struct bq_mgr *bq_mgr, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) bq_mgr, user_data); +} + +static inline void * +bq_mgr_get_user_data(struct bq_mgr *bq_mgr) +{ + return wl_proxy_get_user_data((struct wl_proxy *) bq_mgr); +} + +static inline void +bq_mgr_destroy(struct bq_mgr *bq_mgr) +{ + wl_proxy_destroy((struct wl_proxy *) bq_mgr); +} + +static inline struct bq_consumer * +bq_mgr_create_consumer(struct bq_mgr *bq_mgr, const char *name, int32_t queue_size, int32_t width, int32_t height) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) bq_mgr, + BQ_MGR_CREATE_CONSUMER, &bq_consumer_interface, NULL, name, queue_size, width, height); + + return (struct bq_consumer *) id; +} + +static inline struct bq_provider * +bq_mgr_create_provider(struct bq_mgr *bq_mgr, const char *name) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) bq_mgr, + BQ_MGR_CREATE_PROVIDER, &bq_provider_interface, NULL, name); + + return (struct bq_provider *) id; +} + +struct bq_consumer_listener { + /** + * connected - (none) + */ + void (*connected)(void *data, + struct bq_consumer *bq_consumer); + /** + * disconnected - (none) + */ + void (*disconnected)(void *data, + struct bq_consumer *bq_consumer); + /** + * buffer_attached - (none) + * @buffer: (none) + * @engine: (none) + * @width: (none) + * @height: (none) + * @format: (none) + * @flags: (none) + */ + void (*buffer_attached)(void *data, + struct bq_consumer *bq_consumer, + struct bq_buffer *buffer, + const char *engine, + int32_t width, + int32_t height, + int32_t format, + uint32_t flags); + /** + * set_buffer_id - (none) + * @buffer: (none) + * @id: (none) + * @offset0: (none) + * @stride0: (none) + * @offset1: (none) + * @stride1: (none) + * @offset2: (none) + * @stride2: (none) + */ + void (*set_buffer_id)(void *data, + struct bq_consumer *bq_consumer, + struct bq_buffer *buffer, + int32_t id, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2); + /** + * set_buffer_fd - (none) + * @buffer: (none) + * @fd: (none) + * @offset0: (none) + * @stride0: (none) + * @offset1: (none) + * @stride1: (none) + * @offset2: (none) + * @stride2: (none) + */ + void (*set_buffer_fd)(void *data, + struct bq_consumer *bq_consumer, + struct bq_buffer *buffer, + int32_t fd, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2); + /** + * buffer_detached - (none) + * @buffer: (none) + */ + void (*buffer_detached)(void *data, + struct bq_consumer *bq_consumer, + struct bq_buffer *buffer); + /** + * add_buffer - (none) + * @buffer: (none) + * @serial: (none) + */ + void (*add_buffer)(void *data, + struct bq_consumer *bq_consumer, + struct bq_buffer *buffer, + uint32_t serial); +}; + +static inline int +bq_consumer_add_listener(struct bq_consumer *bq_consumer, + const struct bq_consumer_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) bq_consumer, + (void (**)(void)) listener, data); +} + +#define BQ_CONSUMER_RELEASE_BUFFER 0 + +static inline void +bq_consumer_set_user_data(struct bq_consumer *bq_consumer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) bq_consumer, user_data); +} + +static inline void * +bq_consumer_get_user_data(struct bq_consumer *bq_consumer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) bq_consumer); +} + +static inline void +bq_consumer_destroy(struct bq_consumer *bq_consumer) +{ + wl_proxy_destroy((struct wl_proxy *) bq_consumer); +} + +static inline void +bq_consumer_release_buffer(struct bq_consumer *bq_consumer, struct bq_buffer *buffer) +{ + wl_proxy_marshal((struct wl_proxy *) bq_consumer, + BQ_CONSUMER_RELEASE_BUFFER, buffer); +} + +#ifndef BQ_PROVIDER_ERROR_ENUM +#define BQ_PROVIDER_ERROR_ENUM +enum bq_provider_error { + BQ_PROVIDER_ERROR_OVERFLOW_QUEUE_SIZE = 0, + BQ_PROVIDER_ERROR_CONNECTION = 1, +}; +#endif /* BQ_PROVIDER_ERROR_ENUM */ + +struct bq_provider_listener { + /** + * connected - (none) + * @queue_size: (none) + * @width: (none) + * @height: (none) + */ + void (*connected)(void *data, + struct bq_provider *bq_provider, + int32_t queue_size, + int32_t width, + int32_t height); + /** + * disconnected - (none) + */ + void (*disconnected)(void *data, + struct bq_provider *bq_provider); + /** + * add_buffer - (none) + * @buffer: (none) + * @serial: (none) + */ + void (*add_buffer)(void *data, + struct bq_provider *bq_provider, + struct bq_buffer *buffer, + uint32_t serial); +}; + +static inline int +bq_provider_add_listener(struct bq_provider *bq_provider, + const struct bq_provider_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) bq_provider, + (void (**)(void)) listener, data); +} + +#define BQ_PROVIDER_ATTACH_BUFFER 0 +#define BQ_PROVIDER_SET_BUFFER_ID 1 +#define BQ_PROVIDER_SET_BUFFER_FD 2 +#define BQ_PROVIDER_DETACH_BUFFER 3 +#define BQ_PROVIDER_ENQUEUE_BUFFER 4 + +static inline void +bq_provider_set_user_data(struct bq_provider *bq_provider, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) bq_provider, user_data); +} + +static inline void * +bq_provider_get_user_data(struct bq_provider *bq_provider) +{ + return wl_proxy_get_user_data((struct wl_proxy *) bq_provider); +} + +static inline void +bq_provider_destroy(struct bq_provider *bq_provider) +{ + wl_proxy_destroy((struct wl_proxy *) bq_provider); +} + +static inline struct bq_buffer * +bq_provider_attach_buffer(struct bq_provider *bq_provider, const char *engine, int32_t width, int32_t height, int32_t format, uint32_t flags) +{ + struct wl_proxy *buffer; + + buffer = wl_proxy_marshal_constructor((struct wl_proxy *) bq_provider, + BQ_PROVIDER_ATTACH_BUFFER, &bq_buffer_interface, NULL, engine, width, height, format, flags); + + return (struct bq_buffer *) buffer; +} + +static inline void +bq_provider_set_buffer_id(struct bq_provider *bq_provider, struct bq_buffer *buffer, int32_t id, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2) +{ + wl_proxy_marshal((struct wl_proxy *) bq_provider, + BQ_PROVIDER_SET_BUFFER_ID, buffer, id, offset0, stride0, offset1, stride1, offset2, stride2); +} + +static inline void +bq_provider_set_buffer_fd(struct bq_provider *bq_provider, struct bq_buffer *buffer, int32_t fd, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2) +{ + wl_proxy_marshal((struct wl_proxy *) bq_provider, + BQ_PROVIDER_SET_BUFFER_FD, buffer, fd, offset0, stride0, offset1, stride1, offset2, stride2); +} + +static inline void +bq_provider_detach_buffer(struct bq_provider *bq_provider, struct bq_buffer *buffer) +{ + wl_proxy_marshal((struct wl_proxy *) bq_provider, + BQ_PROVIDER_DETACH_BUFFER, buffer); +} + +static inline void +bq_provider_enqueue_buffer(struct bq_provider *bq_provider, struct bq_buffer *buffer, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) bq_provider, + BQ_PROVIDER_ENQUEUE_BUFFER, buffer, serial); +} + +static inline void +bq_buffer_set_user_data(struct bq_buffer *bq_buffer, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) bq_buffer, user_data); +} + +static inline void * +bq_buffer_get_user_data(struct bq_buffer *bq_buffer) +{ + return wl_proxy_get_user_data((struct wl_proxy *) bq_buffer); +} + +static inline void +bq_buffer_destroy(struct bq_buffer *bq_buffer) +{ + wl_proxy_destroy((struct wl_proxy *) bq_buffer); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_buffer/buffer_queue.c b/src/lib/ecore_buffer/buffer_queue.c new file mode 100644 index 0000000000..241c8396c8 --- /dev/null +++ b/src/lib/ecore_buffer/buffer_queue.c @@ -0,0 +1,153 @@ +#include "buffer_queue.h" + +struct _Ecore_Buffer_Queue +{ + int w, h; + Eina_List *shared_buffers; + Eina_Bool connected; + struct + { + unsigned int capacity; + Eina_List *list; + } queue; +}; + +static Eina_Bool +_queue_is_full(Ecore_Buffer_Queue *ebq) +{ + return (eina_list_count(ebq->queue.list) == ebq->queue.capacity); +} + +static Eina_Bool +_queue_is_empty(Ecore_Buffer_Queue *ebq) +{ + return (eina_list_count(ebq->queue.list) == 0); +} + +Ecore_Buffer_Queue * +_ecore_buffer_queue_new(int w, int h, int queue_size) +{ + Ecore_Buffer_Queue *ebq; + + if (queue_size < 1) return NULL; + + ebq = calloc(1, sizeof(Ecore_Buffer_Queue)); + if (!ebq) + return NULL; + + ebq->w = w; + ebq->h = h; + ebq->queue.capacity = queue_size; + + return ebq; +} + +void +_ecore_buffer_queue_free(Ecore_Buffer_Queue *ebq) +{ + if (!ebq) return; + + if (ebq->shared_buffers) eina_list_free(ebq->shared_buffers); + if (ebq->queue.list) eina_list_free(ebq->queue.list); + free(ebq); +} + +void +_ecore_buffer_queue_enqueue(Ecore_Buffer_Queue *ebq, Shared_Buffer *sb) +{ + if (!ebq) return; + if (_queue_is_full(ebq)) return; + + if (!eina_list_data_find(ebq->shared_buffers, sb)) + { + WARN("Couldn't enqueue not shared buffer."); + return; + } + + ebq->queue.list = eina_list_prepend(ebq->queue.list, sb); +} + +Eina_Bool +_ecore_buffer_queue_dequeue(Ecore_Buffer_Queue *ebq, Shared_Buffer **ret_sb) +{ + Eina_List *last; + Shared_Buffer *sb; + + if (!ebq) return EINA_FALSE; + if (_queue_is_empty(ebq)) return EINA_FALSE; + + sb = eina_list_last_data_get(ebq->queue.list); + last = eina_list_last(ebq->queue.list); + ebq->queue.list = eina_list_remove_list(ebq->queue.list, last); + + if (ret_sb) *ret_sb = sb; + + return EINA_TRUE; +} + +Eina_Bool +_ecore_buffer_queue_is_empty(Ecore_Buffer_Queue *ebq) +{ + if (!ebq) return EINA_FALSE; + + return _queue_is_empty(ebq); +} + +void +_ecore_buffer_queue_shared_buffer_add(Ecore_Buffer_Queue *ebq, Shared_Buffer *sb) +{ + if (!ebq) return; + + ebq->shared_buffers = eina_list_append(ebq->shared_buffers, sb); +} + +void +_ecore_buffer_queue_shared_buffer_remove(Ecore_Buffer_Queue *ebq, Shared_Buffer *sb) +{ + if (!ebq) return; + + ebq->shared_buffers = eina_list_remove(ebq->shared_buffers, sb); + while (eina_list_data_find(ebq->queue.list, sb) != NULL) + ebq->queue.list = eina_list_remove(ebq->queue.list, sb); +} + +Shared_Buffer * +_ecore_buffer_queue_shared_buffer_find(Ecore_Buffer_Queue *ebq, Ecore_Buffer *buffer) +{ + Eina_List *l; + Shared_Buffer *sb; + + if (!ebq) return NULL; + + EINA_LIST_FOREACH(ebq->shared_buffers, l, sb) + { + if (_shared_buffer_buffer_get(sb) == buffer) + return sb; + } + + return NULL; +} + +Eina_List * +_ecore_buffer_queue_shared_buffer_list_get(Ecore_Buffer_Queue *ebq) +{ + if (!ebq) return NULL; + + return ebq->shared_buffers; +} + +void +_ecore_buffer_queue_connection_state_set(Ecore_Buffer_Queue *ebq, Eina_Bool connect) +{ + if (!ebq) return; + + ebq->connected = connect; +} + +Eina_Bool +_ecore_buffer_queue_connection_state_get(Ecore_Buffer_Queue *ebq) +{ + if (!ebq) return EINA_FALSE; + + return ebq->connected; +} diff --git a/src/lib/ecore_buffer/buffer_queue.h b/src/lib/ecore_buffer/buffer_queue.h new file mode 100644 index 0000000000..f4f551fb6b --- /dev/null +++ b/src/lib/ecore_buffer/buffer_queue.h @@ -0,0 +1,23 @@ +#ifndef _BUFFER_QUEUE_H_ +#define _BUFFER_QUEUE_H_ + +#include +#include + +#include "shared_buffer.h" + +typedef struct _Ecore_Buffer_Queue Ecore_Buffer_Queue; + +Ecore_Buffer_Queue *_ecore_buffer_queue_new(int w, int h, int queue_size); +void _ecore_buffer_queue_free(Ecore_Buffer_Queue *ebq); +void _ecore_buffer_queue_enqueue(Ecore_Buffer_Queue *ebq, Shared_Buffer *sb); +Eina_Bool _ecore_buffer_queue_dequeue(Ecore_Buffer_Queue *ebq, Shared_Buffer **ret_sb); +Eina_Bool _ecore_buffer_queue_is_empty(Ecore_Buffer_Queue *ebq); +void _ecore_buffer_queue_shared_buffer_add(Ecore_Buffer_Queue *ebq, Shared_Buffer *sb); +void _ecore_buffer_queue_shared_buffer_remove(Ecore_Buffer_Queue *ebq, Shared_Buffer *sb); +Shared_Buffer *_ecore_buffer_queue_shared_buffer_find(Ecore_Buffer_Queue *ebq, Ecore_Buffer *buffer); +Eina_List *_ecore_buffer_queue_shared_buffer_list_get(Ecore_Buffer_Queue *ebq); +void _ecore_buffer_queue_connection_state_set(Ecore_Buffer_Queue *ebq, Eina_Bool connect); +Eina_Bool _ecore_buffer_queue_connection_state_get(Ecore_Buffer_Queue *ebq); + +#endif diff --git a/src/lib/ecore_buffer/ecore_buffer.c b/src/lib/ecore_buffer/ecore_buffer.c new file mode 100644 index 0000000000..caa8f87659 --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer.c @@ -0,0 +1,491 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "Eina.h" +#include "Ecore.h" + +#include "Ecore_Buffer.h" +#include "ecore_buffer_private.h" + +typedef struct _Ecore_Buffer_Module Ecore_Buffer_Module; +typedef struct _Ecore_Buffer_Cb_Data Ecore_Buffer_Cb_Data; + +struct _Ecore_Buffer_Module +{ + Ecore_Buffer_Backend *be; + Ecore_Buffer_Module_Data data; +}; + +struct _Ecore_Buffer +{ + unsigned int width; + unsigned int height; + int format; + unsigned int flags; + + Ecore_Buffer_Data buffer_data; + Ecore_Buffer_Module *bm; + + Eina_Hash *data; + Eina_Inlist *free_callbacks; +}; + +struct _Ecore_Buffer_Cb_Data +{ + EINA_INLIST; + Ecore_Buffer_Cb cb; + void *data; +}; + +static Eina_Hash *_backends; +static Eina_Array *_modules; +static int _ecore_buffer_init_count = 0; +static int _ecore_buffer_log_dom = -1; + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_buffer_log_dom, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_buffer_log_dom, __VA_ARGS__) + +#ifndef PACKAGE_LIB_DIR +#define PACKAGE_LIB_DIR "" +#endif +#ifndef MODULE_ARCH +#define MODULE_ARCH "" +#endif + +static Ecore_Buffer_Module * +_ecore_buffer_get_backend(const char *name) +{ + Ecore_Buffer_Module *bm = NULL; + Eina_Iterator *backend_name_itr; + const char *backend_name = NULL; + + backend_name = name; + + if (backend_name == NULL) + { + backend_name = (const char*)getenv("ECORE_BUFFER_ENGINE"); + if (!backend_name) + { + backend_name_itr = eina_hash_iterator_data_new(_backends); + while((!bm) && + (eina_iterator_next(backend_name_itr, (void **)&bm))); + eina_iterator_free(backend_name_itr); + } + } + else + bm = eina_hash_find(_backends, backend_name); + + if ((!bm) || (!bm->be)) + return NULL; + + if (bm->be->init) + bm->data = bm->be->init(NULL, NULL); + + return bm; +} + +static Eina_Bool +_ecore_buffer_backends_free(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED) +{ + Ecore_Buffer_Module *bm = data; + + if (!bm) + return EINA_FALSE; + + if (bm->data) + bm->be->shutdown(bm->data); + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_buffer_register(Ecore_Buffer_Backend *be) +{ + Ecore_Buffer_Module *bm; + + EINA_SAFETY_ON_NULL_RETURN_VAL(be, 0); + + bm = calloc(1, sizeof(Ecore_Buffer_Module)); + if (!bm) + return EINA_FALSE; + + bm->be = be; + bm->data = NULL; + + return eina_hash_add(_backends, be->name, bm); +} + +EAPI void +ecore_buffer_unregister(Ecore_Buffer_Backend *be) +{ + Ecore_Buffer_Module *bm; + + EINA_SAFETY_ON_NULL_RETURN(be); + + bm = eina_hash_find(_backends, be->name); + if (!bm) + return; + + eina_hash_del(_backends, be->name, bm); + free(bm); +} + +EAPI Eina_Bool +ecore_buffer_init(void) +{ + char *path; + + if (++_ecore_buffer_init_count > 1) + return EINA_TRUE; + + _ecore_buffer_log_dom = eina_log_domain_register("ecore_buffer", EINA_COLOR_BLUE); + if (_ecore_buffer_log_dom < 0) + { + EINA_LOG_ERR("Could not register log domain: ecore_buffer"); + goto err; + } + + _backends = eina_hash_string_superfast_new(NULL); + + /* dynamic backends */ + _modules = eina_module_arch_list_get(NULL, + PACKAGE_LIB_DIR "/ecore_buffer/modules", + MODULE_ARCH); + + path = eina_module_symbol_path_get((const void *)ecore_buffer_init, + "/ecore_buffer/modules"); + + _modules = eina_module_arch_list_get(_modules, path, MODULE_ARCH); + if (path) + free(path); + + /* fallback using module where in build directory */ + if ((!_modules) || + (eina_array_count(_modules) == 0)) + { + ERR("No available module in library directy: %s", + PACKAGE_LIB_DIR "/ecore_buffer/modules"); + ERR("Fallback to load module where in build directory :%s", + PACKAGE_BUILD_DIR "/src/modules/"); + _modules = eina_module_list_get(NULL, + PACKAGE_BUILD_DIR "/src/modules/", + EINA_TRUE, NULL, NULL); + } + + if ((!_modules) || + (eina_array_count(_modules) == 0)) + { + ERR("no ecore_buffer modules able to be loaded."); + eina_hash_free(_backends); + eina_log_domain_unregister(_ecore_buffer_log_dom); + _ecore_buffer_log_dom = -1; + goto err; + } + + // XXX: MODFIX: do not list ALL modules and load them ALL! this is + // wrong. load the module we need WHEN we need it (by name etc. etc. + // from api). + eina_module_list_load(_modules); + + return EINA_TRUE; + +err: + _ecore_buffer_init_count--; + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_buffer_shutdown(void) +{ + if (_ecore_buffer_init_count < 1) + { + WARN("Ecore_Buffer shut down called without init"); + return EINA_FALSE; + } + + if (--_ecore_buffer_init_count != 0) + return EINA_FALSE; + + /* dynamic backends */ + eina_hash_foreach(_backends, _ecore_buffer_backends_free, NULL); + + eina_module_list_free(_modules); + if (_modules) + eina_array_free(_modules); + + if (_backends) + eina_hash_free(_backends); + + eina_log_domain_unregister(_ecore_buffer_log_dom); + _ecore_buffer_log_dom = -1; + + return EINA_TRUE; +} + +EAPI Ecore_Buffer* +ecore_buffer_new(const char *engine, unsigned int width, unsigned int height, Ecore_Buffer_Format format, unsigned int flags) +{ + Ecore_Buffer_Module *bm; + Ecore_Buffer *bo; + void *bo_data; + + bm = _ecore_buffer_get_backend(engine); + if (!bm) + { + ERR("Failed to get backend: %s", engine); + return NULL; + } + + EINA_SAFETY_ON_NULL_RETURN_VAL(bm->be, NULL); + + if (!bm->be->buffer_alloc) + { + ERR("Not supported create buffer"); + return NULL; + } + + bo = calloc(1, sizeof(Ecore_Buffer)); + if (!bo) + return NULL; + + bo_data = bm->be->buffer_alloc(bm->data, width, height, format, flags); + if (!bo_data) + { + free(bo); + return NULL; + } + + bo->bm = bm; + bo->width = width; + bo->height = height; + bo->format = format; + bo->flags = flags; + bo->buffer_data = bo_data; + + return bo; +} + +EAPI void +ecore_buffer_free(Ecore_Buffer *buf) +{ + Ecore_Buffer_Cb_Data *free_cb; + + EINA_SAFETY_ON_NULL_RETURN(buf); + + //Call free_cb + while (buf->free_callbacks) + { + free_cb = EINA_INLIST_CONTAINER_GET(buf->free_callbacks, Ecore_Buffer_Cb_Data); + buf->free_callbacks = eina_inlist_remove(buf->free_callbacks, buf->free_callbacks); + + free_cb->cb(buf, free_cb->data); + free(free_cb); + } + + EINA_SAFETY_ON_NULL_RETURN(buf->bm); + EINA_SAFETY_ON_NULL_RETURN(buf->bm->be); + EINA_SAFETY_ON_NULL_RETURN(buf->bm->be->buffer_free); + + buf->bm->be->buffer_free(buf->bm->data, buf->buffer_data); + + //Free User Data + if (buf->data) + eina_hash_free(buf->data); + + free(buf); +} + +EAPI void * +ecore_buffer_data_get(Ecore_Buffer *buf) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, NULL); + + if (!buf->bm->be->data_get) + return NULL; + + return buf->bm->be->data_get(buf->bm->data, buf->buffer_data); +} + +EAPI Ecore_Pixmap +ecore_buffer_pixmap_get(Ecore_Buffer *buf) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, 0); + + if (!buf->bm->be->pixmap_get) + return 0; + + return buf->bm->be->pixmap_get(buf->bm->data, buf->buffer_data); +} + +EAPI void * +ecore_buffer_tbm_surface_get(Ecore_Buffer *buf) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, NULL); + + if (!buf->bm->be->tbm_surface_get) + { + ERR("TBM is not supported\n"); + return NULL; + } + + return buf->bm->be->tbm_surface_get(buf->bm->data, buf->buffer_data); +} + +EAPI Eina_Bool +ecore_buffer_size_get(Ecore_Buffer *buf, unsigned int *width, unsigned int *height) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, EINA_FALSE); + + if (width) *width = buf->width; + if (height) *height = buf->height; + + return EINA_TRUE; +} + +EAPI unsigned int +ecore_buffer_format_get(Ecore_Buffer *buf) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0); + + return buf->format; +} + +EAPI unsigned int +ecore_buffer_flags_get(Ecore_Buffer *buf) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0); + + return buf->flags; +} + +EAPI void +ecore_buffer_free_callback_add(Ecore_Buffer *buf, Ecore_Buffer_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(buf); + EINA_SAFETY_ON_NULL_RETURN(func); + + Ecore_Buffer_Cb_Data *free_cb; + + free_cb = calloc(1, sizeof(Ecore_Buffer_Cb_Data)); + if (!free_cb) + return; + + free_cb->cb = func; + free_cb->data = data; + buf->free_callbacks = eina_inlist_append(buf->free_callbacks, EINA_INLIST_GET(free_cb)); +} + +EAPI void +ecore_buffer_free_callback_remove(Ecore_Buffer *buf, Ecore_Buffer_Cb func, void *data) +{ + Ecore_Buffer_Cb_Data *free_cb; + + EINA_SAFETY_ON_NULL_RETURN(buf); + EINA_SAFETY_ON_NULL_RETURN(func); + + if (buf->free_callbacks) + { + Eina_Inlist *itrn; + EINA_INLIST_FOREACH_SAFE(buf->free_callbacks, itrn, free_cb) + { + if (free_cb->cb == func && free_cb->data == data) + { + buf->free_callbacks = + eina_inlist_remove(buf->free_callbacks, + EINA_INLIST_GET(free_cb)); + free(free_cb); + } + } + } +} + +const char * +_ecore_buffer_engine_name_get(Ecore_Buffer *buf) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, 0); + + return buf->bm->be->name; +} + +Ecore_Export_Type +_ecore_buffer_export(Ecore_Buffer *buf, int *id) +{ + Ecore_Export_Type type = EXPORT_TYPE_INVALID; + int ret_id; + + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, type); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, type); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, type); + + if (!buf->bm->be->buffer_export) + return type; + + type = buf->bm->be->buffer_export(buf->bm->data, buf->buffer_data, &ret_id); + + if (id) *id = ret_id; + + return type; +} + +Ecore_Buffer * +_ecore_buffer_import(const char *engine, int width, int height, Ecore_Buffer_Format format, Ecore_Export_Type type, int export_id, unsigned int flags) +{ + Ecore_Buffer_Module *bm; + Ecore_Buffer *bo; + void *bo_data; + + bm = _ecore_buffer_get_backend(engine); + if (!bm) + { + ERR("Filed to get Backend: %s", engine); + return NULL; + } + + EINA_SAFETY_ON_NULL_RETURN_VAL(bm->be, NULL); + + if (!bm->be->buffer_import) + { + ERR("Not supported import buffer"); + return NULL; + } + + bo = calloc(1, sizeof(Ecore_Buffer)); + if (!bo) + return NULL; + + bo_data = bm->be->buffer_import(bm->data, width, height, format, type, export_id, flags); + if (!bo_data) + { + free(bo); + return NULL; + } + + bo->bm = bm; + bo->width = width; + bo->height = height; + bo->format = format; + bo->flags = flags; + bo->buffer_data = bo_data; + + return bo; +} diff --git a/src/lib/ecore_buffer/ecore_buffer_con.c b/src/lib/ecore_buffer/ecore_buffer_con.c new file mode 100644 index 0000000000..7cc4bc5103 --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer_con.c @@ -0,0 +1,253 @@ +#include "ecore_buffer_con.h" + +#define DEBUG 1 + +typedef struct _Ecore_Buffer_Con Ecore_Buffer_Con; + +struct _Ecore_Buffer_Con +{ + struct wl_display *display; + struct wl_registry *registry; + struct bq_mgr *bq_mgr; + Ecore_Fd_Handler *fd_hdl; + Ecore_Idle_Enterer *idle_enterer; + int fd; + Eina_Bool init_done; +}; + +static Eina_Bool _connection_fatal_error = EINA_FALSE; +Ecore_Buffer_Con *_connection = NULL; + +static void +_ecore_buffer_con_cb_registry_global(void *data, struct wl_registry *wl_registry, uint32_t id, const char *interface, uint32_t version) +{ + Ecore_Buffer_Con *conn = data; + + DBG("Added Wl Global Registry - name %d interface %s version %d", + id, interface, version); + + if (!strncmp(interface, "bq_mgr", strlen("bq_mgr"))) + { + conn->bq_mgr = + wl_registry_bind(wl_registry, id, &bq_mgr_interface, 1); + } +} + +static void +_ecore_buffer_con_cb_registry_global_remove(void *data EINA_UNUSED, struct wl_registry *wl_registry EINA_UNUSED, uint32_t name EINA_UNUSED) +{ + DBG("Removed Wl Global Registry - name %d", name); +} + +static void +_ecore_buffer_con_signal_exit_free(void *data EINA_UNUSED, void *event) +{ + free(event); +} + +static void +_ecore_buffer_con_signal_exit(void) +{ + Ecore_Event_Signal_Exit *ev; + + if (!(ev = calloc(1, sizeof(Ecore_Event_Signal_Exit)))) + return; + + ev->quit = 1; + ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, ev, + _ecore_buffer_con_signal_exit_free, NULL); +} + +static Eina_Bool +_ecore_buffer_con_cb_idle_enterer(void *data) +{ + Ecore_Buffer_Con *conn; + int ret = 0; + + if (_connection_fatal_error) return ECORE_CALLBACK_CANCEL; + + if (!(conn = data)) return ECORE_CALLBACK_RENEW; + + ret = wl_display_get_error(conn->display); + if (ret < 0) goto err; + + ret = wl_display_flush(conn->display); + if ((ret < 0) && (errno == EAGAIN)) + ecore_main_fd_handler_active_set(conn->fd_hdl, + (ECORE_FD_READ | ECORE_FD_WRITE)); + + ret = wl_display_dispatch_pending(conn->display); + if (ret < 0) goto err; + + return ECORE_CALLBACK_RENEW; + +err: + if ((ret < 0) && ((errno != EAGAIN) && (errno != EINVAL))) + { + _connection_fatal_error = EINA_TRUE; + + /* raise exit signal */ + _ecore_buffer_con_signal_exit(); + + return ECORE_CALLBACK_CANCEL; + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_buffer_con_cb_fd_handle(void *data, Ecore_Fd_Handler *hdl) +{ + Ecore_Buffer_Con *conn = data; + int ret = 0; + + if (_connection_fatal_error) return ECORE_CALLBACK_CANCEL; + if (!conn) return ECORE_CALLBACK_RENEW; + + if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_ERROR)) + { + ERR("Received error on wayland display fd"); + _connection_fatal_error = EINA_TRUE; + _ecore_buffer_con_signal_exit(); + + return ECORE_CALLBACK_CANCEL; + } + + if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_READ)) + ret = wl_display_dispatch(conn->display); + else if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_WRITE)) + { + ret = wl_display_flush(conn->display); + if (ret == 0) + ecore_main_fd_handler_active_set(hdl, ECORE_FD_READ); + } + + if ((ret < 0) && ((errno != EAGAIN) && (errno != EINVAL))) + { + _connection_fatal_error = EINA_TRUE; + + /* raise exit signal */ + _ecore_buffer_con_signal_exit(); + + return ECORE_CALLBACK_CANCEL; + } + + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_buffer_con_init_callback(void *data, struct wl_callback *callback, uint32_t serial EINA_UNUSED) +{ + Ecore_Buffer_Con *conn = data; + + DBG("Queue Server Connected"); + + if (!conn) + return; + + wl_callback_destroy(callback); + conn->init_done = EINA_TRUE; +} + +static const struct wl_callback_listener _ecore_buffer_con_init_sync_listener = +{ + _ecore_buffer_con_init_callback +}; + +struct wl_registry_listener _ecore_buffer_registry_listener = +{ + _ecore_buffer_con_cb_registry_global, + _ecore_buffer_con_cb_registry_global_remove +}; + +Eina_Bool +_ecore_buffer_con_init(void) +{ + struct wl_callback *callback; + const char *name = "bq_mgr_daemon"; + + DBG("Ecore_Buffer_Con Init - name %s", name); + + _connection = calloc(1, sizeof(Ecore_Buffer_Con)); + if (!_connection) + { + ERR("Failed to allocation"); + return EINA_FALSE; + } + + if (!(_connection->display = wl_display_connect(name))) + { + ERR("Failed to connect to Queue Server"); + goto err_connect; + } + + _connection->fd = wl_display_get_fd(_connection->display); + _connection->fd_hdl = + ecore_main_fd_handler_add(_connection->fd, + ECORE_FD_READ | ECORE_FD_WRITE | ECORE_FD_ERROR, + _ecore_buffer_con_cb_fd_handle, + _connection, NULL, NULL); + + _connection->idle_enterer = + ecore_idle_enterer_add(_ecore_buffer_con_cb_idle_enterer, _connection); + + if (!(_connection->registry = wl_display_get_registry(_connection->display))) + goto err_get_registry; + + wl_registry_add_listener(_connection->registry, + &_ecore_buffer_registry_listener, _connection); + + _connection->init_done = EINA_FALSE; + callback = wl_display_sync(_connection->display); + wl_callback_add_listener(callback, &_ecore_buffer_con_init_sync_listener, + _connection); + + return EINA_TRUE;; +err_get_registry: + wl_display_disconnect(_connection->display); +err_connect: + free(_connection); + return EINA_FALSE; +} + +void +_ecore_buffer_con_shutdown(void) +{ + if (!_connection) return; + + DBG("Ecore_Buffer_Con Shutdown"); + + if (_connection->fd_hdl) + ecore_main_fd_handler_del(_connection->fd_hdl); + + if (_connection->idle_enterer) + ecore_idle_enterer_del(_connection->idle_enterer); + + if (_connection->bq_mgr) + bq_mgr_destroy(_connection->bq_mgr); + + if (_connection->display) + wl_display_disconnect(_connection->display); + + free(_connection); + _connection = NULL; +} + +struct bq_provider * +_ecore_buffer_con_provider_create(const char *name) +{ + return bq_mgr_create_provider(_connection->bq_mgr, name); +} + +struct bq_consumer * +_ecore_buffer_con_consumer_create(const char *name, int queue_size, int w, int h) +{ + return bq_mgr_create_consumer(_connection->bq_mgr, name, queue_size, w, h); +} + +void +_ecore_buffer_con_init_wait(void) +{ + while (!_connection->init_done) + wl_display_dispatch(_connection->display); +} diff --git a/src/lib/ecore_buffer/ecore_buffer_con.h b/src/lib/ecore_buffer/ecore_buffer_con.h new file mode 100644 index 0000000000..f38d4e0a38 --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer_con.h @@ -0,0 +1,20 @@ +#ifndef _ECORE_BUFFER_con_H_ +#define _ECORE_BUFFER_con_H_ + +#include +#include + +#include +#include +#include + +#include "bq_mgr_protocol.h" +#include "ecore_buffer_private.h" + +Eina_Bool _ecore_buffer_con_init(void); +void _ecore_buffer_con_shutdown(void); +void _ecore_buffer_con_init_wait(void); +struct bq_provider *_ecore_buffer_con_provider_create(const char *name); +struct bq_consumer *_ecore_buffer_con_consumer_create(const char *name, int queue_size, int w, int h); + +#endif diff --git a/src/lib/ecore_buffer/ecore_buffer_consumer.c b/src/lib/ecore_buffer/ecore_buffer_consumer.c new file mode 100644 index 0000000000..59a4a046cf --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer_consumer.c @@ -0,0 +1,417 @@ +#include +#include + +#include +#include +#include + +#include "bq_mgr_protocol.h" +#include "shared_buffer.h" +#include "buffer_queue.h" +#include "ecore_buffer_private.h" +#include "ecore_buffer_con.h" + +struct _Ecore_Buffer_Consumer +{ + struct bq_consumer *resource; + Ecore_Buffer_Queue *ebq; + struct + { + void (*provider_add) (Ecore_Buffer_Consumer *consumer, void *data); + void (*provider_del) (Ecore_Buffer_Consumer *consumer, void *data); + void (*enqueue) (Ecore_Buffer_Consumer *consumer, void *data); + void *data; + } cb; +}; + +static void _ecore_buffer_consumer_cb_provider_connected(void *data, struct bq_consumer *bq_consumer); +static void _ecore_buffer_consumer_cb_provider_disconnected(void *data, struct bq_consumer *bq_consumer); +static void _ecore_buffer_consumer_cb_buffer_attached(void *data, struct bq_consumer *bq_consumer, struct bq_buffer *id, const char *engine, int32_t width, int32_t height, int32_t format, uint32_t flags); +static void _ecore_buffer_consumer_cb_buffer_id_set(void *data, struct bq_consumer *bq_consumer, struct bq_buffer *buffer, int32_t id, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2); +static void _ecore_buffer_consumer_cb_buffer_fd_set(void *data, struct bq_consumer *bq_consumer, struct bq_buffer *buffer, int32_t fd, int32_t offset0, int32_t stride0, int32_t offset1, int32_t stride1, int32_t offset2, int32_t stride2); +static void _ecore_buffer_consumer_cb_buffer_detached(void *data, struct bq_consumer *bq_consumer, struct bq_buffer *id); +static void _ecore_buffer_consumer_cb_add_buffer(void *data, struct bq_consumer *bq_consumer, struct bq_buffer *buffer, uint32_t serial); +static void _ecore_buffer_consumer_cb_buffer_free(Ecore_Buffer *buf, void *data); +static Eina_Bool _ecore_buffer_consumer_buffer_import(Ecore_Buffer_Consumer *consumer, Shared_Buffer *sb, int32_t seed, Ecore_Export_Type export_type); + +struct bq_consumer_listener _ecore_buffer_consumer_listener = +{ + _ecore_buffer_consumer_cb_provider_connected, + _ecore_buffer_consumer_cb_provider_disconnected, + _ecore_buffer_consumer_cb_buffer_attached, + _ecore_buffer_consumer_cb_buffer_id_set, + _ecore_buffer_consumer_cb_buffer_fd_set, + _ecore_buffer_consumer_cb_buffer_detached, + _ecore_buffer_consumer_cb_add_buffer +}; + +EAPI Ecore_Buffer_Consumer * +ecore_buffer_consumer_new(const char *name, int32_t queue_size, int32_t w, int32_t h) +{ + Ecore_Buffer_Consumer *consumer; + const int default_queue_size = 2; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + DBG("Consumer New - name %s, queue size %d, size (%dx%d)", + name, queue_size, w, h); + + if ((w < 1) || (h < 1)) + return NULL; + + if (queue_size < default_queue_size) + queue_size = default_queue_size; + + _ecore_buffer_con_init_wait(); + + consumer = calloc(1, sizeof(Ecore_Buffer_Consumer)); + if (!consumer) + return NULL; + + consumer->ebq = _ecore_buffer_queue_new(w, h, queue_size); + if (!consumer->ebq) + { + free(consumer); + return NULL; + } + + consumer->resource = _ecore_buffer_con_consumer_create(name, queue_size, w, h); + if (!consumer->resource) + { + _ecore_buffer_queue_free(consumer->ebq); + free(consumer); + return NULL; + } + + bq_consumer_add_listener(consumer->resource, + &_ecore_buffer_consumer_listener, + consumer); + + return consumer; +} + +EAPI void +ecore_buffer_consumer_free(Ecore_Buffer_Consumer *consumer) +{ + EINA_SAFETY_ON_NULL_RETURN(consumer); + + DBG("Consumer Free"); + + if (consumer->ebq) + _ecore_buffer_queue_free(consumer->ebq); + + if (consumer->resource) + bq_consumer_destroy(consumer->resource); + + free(consumer); +} + +EAPI Eina_Bool +ecore_buffer_consumer_buffer_release(Ecore_Buffer_Consumer *consumer, Ecore_Buffer *buffer) +{ + Shared_Buffer *sb; + + EINA_SAFETY_ON_NULL_RETURN_VAL(consumer, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(buffer, EINA_FALSE); + + DBG("Buffer Release"); + + if (!_ecore_buffer_queue_connection_state_get(consumer->ebq)) + { + WARN("NOT Connected with provider yet"); + return EINA_FALSE; + } + + if (!(sb = _ecore_buffer_queue_shared_buffer_find(consumer->ebq, buffer))) + { + WARN("NOT shared - buffer %p", buffer); + return EINA_FALSE; + } + + // already detached buffer, free buffer by deputy. + if (_shared_buffer_state_get(sb) == SHARED_BUFFER_STATE_DETACH) + { + DBG("Free buffer - buffer %p", sb); + ecore_buffer_free(buffer); + } + else + { + if (_shared_buffer_state_get(sb) != SHARED_BUFFER_STATE_DEQUEUE) + { + WARN("Failed to Release Buffer -" + "DO NOT Release buffer which is not Dequeued: buffer %p state %s", + sb, _shared_buffer_state_string_get(sb)); + return EINA_FALSE; + } + + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_RELEASE); + bq_consumer_release_buffer(consumer->resource, _shared_buffer_resource_get(sb)); + } + + return EINA_TRUE; +} + +EAPI Ecore_Buffer * +ecore_buffer_consumer_buffer_dequeue(Ecore_Buffer_Consumer *consumer) +{ + Shared_Buffer *sb; + + EINA_SAFETY_ON_NULL_RETURN_VAL(consumer, EINA_FALSE); + + DBG("Buffer Acquire"); + + if (!_ecore_buffer_queue_dequeue(consumer->ebq, &sb)) + { + DBG("No Available Buffer in Queue"); + return NULL; + } + + // This should not happen. + if (_shared_buffer_state_get(sb) != SHARED_BUFFER_STATE_ENQUEUE) + { + ERR("Unknown error occured - Not on Enqueued State: buffer %p, state %s", + sb, _shared_buffer_state_string_get(sb)); + return NULL; + } + + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_DEQUEUE); + + return _shared_buffer_buffer_get(sb); +} + +EAPI Eina_Bool +ecore_buffer_consumer_queue_is_empty(Ecore_Buffer_Consumer *consumer) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(consumer, EINA_FALSE); + + return _ecore_buffer_queue_is_empty(consumer->ebq); +} + +EAPI void +ecore_buffer_consumer_provider_add_cb_set(Ecore_Buffer_Consumer *consumer, Ecore_Buffer_Consumer_Provider_Add_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(consumer); + + consumer->cb.provider_add = func; + consumer->cb.data = data; +} + +EAPI void +ecore_buffer_consumer_provider_del_cb_set(Ecore_Buffer_Consumer *consumer, Ecore_Buffer_Consumer_Provider_Del_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(consumer); + + consumer->cb.provider_del = func; + consumer->cb.data = data; +} + +EAPI void +ecore_buffer_consumer_buffer_enqueued_cb_set(Ecore_Buffer_Consumer *consumer, Ecore_Buffer_Consumer_Enqueue_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(consumer); + + consumer->cb.enqueue = func; + consumer->cb.data = data; +} + +static void +_ecore_buffer_consumer_cb_provider_connected(void *data, struct bq_consumer *bq_consumer EINA_UNUSED) +{ + Ecore_Buffer_Consumer *consumer = data; + + EINA_SAFETY_ON_NULL_RETURN(consumer); + + DBG("Provider Connected"); + + _ecore_buffer_queue_connection_state_set(consumer->ebq, EINA_TRUE); + + CALLBACK_CALL(consumer, provider_add); +} + +static void +_ecore_buffer_consumer_cb_provider_disconnected(void *data, struct bq_consumer *bq_consumer EINA_UNUSED) +{ + Ecore_Buffer_Consumer *consumer = data; + Eina_List *clone, *shared_buffers, *l; + Shared_Buffer *sb; + + EINA_SAFETY_ON_NULL_RETURN(consumer); + + DBG("Provider Disconnected"); + + _ecore_buffer_queue_connection_state_set(consumer->ebq, EINA_FALSE); + + CALLBACK_CALL(consumer, provider_del); + + shared_buffers = _ecore_buffer_queue_shared_buffer_list_get(consumer->ebq); + clone = eina_list_clone(shared_buffers); + + EINA_LIST_FOREACH(clone, l, sb) + ecore_buffer_free(_shared_buffer_buffer_get(sb)); + + eina_list_free(clone); +} + +static void +_ecore_buffer_consumer_cb_buffer_attached(void *data, struct bq_consumer *bq_consumer EINA_UNUSED, struct bq_buffer *id, const char *engine, int32_t width, int32_t height, int32_t format, uint32_t flags) +{ + Ecore_Buffer_Consumer *consumer = data; + Shared_Buffer *sb; + + EINA_SAFETY_ON_NULL_RETURN(consumer); + EINA_SAFETY_ON_NULL_RETURN(consumer->ebq); + + DBG("Buffer Attached - engine %s, size (%dx%d), format %d, flags %d", + engine, width, height, format, flags); + + sb = _shared_buffer_new(engine, id, width, height, format, flags); + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_ATTACH); + _ecore_buffer_queue_shared_buffer_add(consumer->ebq, sb); + bq_buffer_set_user_data(id, sb); +} + +static void +_ecore_buffer_consumer_cb_buffer_free(Ecore_Buffer *buf, void *data) +{ + Ecore_Buffer_Consumer *consumer = data; + Shared_Buffer *sb; + + EINA_SAFETY_ON_NULL_RETURN(buf); + EINA_SAFETY_ON_NULL_RETURN(consumer); + + sb = _ecore_buffer_queue_shared_buffer_find(consumer->ebq, buf); + if (!sb) + return; + + _ecore_buffer_queue_shared_buffer_remove(consumer->ebq, sb); + bq_buffer_destroy(_shared_buffer_resource_get(sb)); + _shared_buffer_free(sb); +} + +static void +_ecore_buffer_consumer_cb_buffer_id_set(void *data, struct bq_consumer *bq_consumer EINA_UNUSED, struct bq_buffer *buffer, int32_t id, int32_t offset0 EINA_UNUSED, int32_t stride0 EINA_UNUSED, int32_t offset1 EINA_UNUSED, int32_t stride1 EINA_UNUSED, int32_t offset2 EINA_UNUSED, int32_t stride2 EINA_UNUSED) +{ + Ecore_Buffer_Consumer *consumer = data; + Shared_Buffer *sb = bq_buffer_get_user_data(buffer); + + EINA_SAFETY_ON_NULL_RETURN(consumer); + EINA_SAFETY_ON_NULL_RETURN(sb); + + if (_ecore_buffer_consumer_buffer_import(consumer, sb, id, EXPORT_TYPE_ID)) + bq_buffer_set_user_data(buffer, sb); + else + ERR("Failed to import buffer - buffer resource %p", buffer); +} + +static void +_ecore_buffer_consumer_cb_buffer_fd_set(void *data, struct bq_consumer *bq_consumer EINA_UNUSED, struct bq_buffer *buffer, int32_t fd, int32_t offset0 EINA_UNUSED, int32_t stride0 EINA_UNUSED, int32_t offset1 EINA_UNUSED, int32_t stride1 EINA_UNUSED, int32_t offset2 EINA_UNUSED, int32_t stride2 EINA_UNUSED) +{ + Ecore_Buffer_Consumer *consumer = data; + Shared_Buffer *sb = bq_buffer_get_user_data(buffer); + + EINA_SAFETY_ON_NULL_RETURN(consumer); + EINA_SAFETY_ON_NULL_RETURN(sb); + + if (_ecore_buffer_consumer_buffer_import(consumer, sb, fd, EXPORT_TYPE_FD)) + bq_buffer_set_user_data(buffer, sb); + else + ERR("Failed to import buffer - buffer resource %p", buffer); +} + +static void +_ecore_buffer_consumer_cb_buffer_detached(void *data, struct bq_consumer *bq_consumer EINA_UNUSED, struct bq_buffer *id) +{ + Ecore_Buffer_Consumer *consumer = data; + Shared_Buffer *sb = bq_buffer_get_user_data(id); + + EINA_SAFETY_ON_NULL_RETURN(consumer); + EINA_SAFETY_ON_NULL_RETURN(sb); + + DBG("Buffer Detached"); + + // buffer is owned by consumer. free right now. + if (_shared_buffer_state_get(sb) != SHARED_BUFFER_STATE_DEQUEUE) + { + DBG("Free buffer - buffer %p, state %s", + sb, _shared_buffer_state_string_get(sb)); + ecore_buffer_free(_shared_buffer_buffer_get(sb)); + return; + } + + // mark it as a detached buffer, and then free on buffer release time. + DBG("Just mark this buffer to free it when released - buffer %p, state %s", + sb, "SHARED_BUFFER_STATE_DEQUEUE"); + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_DETACH); +} + +static void +_ecore_buffer_consumer_cb_add_buffer(void *data, struct bq_consumer *bq_consumer EINA_UNUSED, struct bq_buffer *buffer, uint32_t serial EINA_UNUSED) +{ + Ecore_Buffer_Consumer *consumer = data; + Shared_Buffer *sb = bq_buffer_get_user_data(buffer); + Shared_Buffer_State state; + + EINA_SAFETY_ON_NULL_RETURN(consumer); + + DBG("Buffer Enqueued"); + + if (!sb) + { + ERR("Unknown Error occured - maybe this buffer is not shared yet"); + return; + } + + state = _shared_buffer_state_get(sb); + if ((state != SHARED_BUFFER_STATE_IMPORT) && + (state != SHARED_BUFFER_STATE_RELEASE)) + { + ERR("Unknown Error occured - Could not enqueued this state of buffer: buffer %p, state %s", + sb, _shared_buffer_state_string_get(sb)); + return; + } + + _ecore_buffer_queue_enqueue(consumer->ebq, sb); + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_ENQUEUE); + + CALLBACK_CALL(consumer, enqueue); +} + +static Eina_Bool +_ecore_buffer_consumer_buffer_import(Ecore_Buffer_Consumer *consumer, Shared_Buffer *sb, int32_t seed, Ecore_Export_Type export_type) +{ + Ecore_Buffer *buffer; + const char *engine = NULL; + int w, h, format; + unsigned int flags; + + if ((!sb) || + (!_shared_buffer_info_get(sb, &engine, &w, &h, &format, &flags))) + { + ERR("Failed to Get Shared Buffer"); + return EINA_FALSE; + } + + if (_shared_buffer_state_get(sb) != SHARED_BUFFER_STATE_ATTACH) + { + ERR("Not Attached Buffer - buffer %p state %s", + sb, _shared_buffer_state_string_get(sb)); + return EINA_FALSE; + } + + if (!(buffer = _ecore_buffer_import(engine, w, h, format, export_type, seed, flags))) + { + ERR("Failed to Import Buffer - size (%dx%d), foramt %d, seed %d, export_type %d", + w, h, format, seed, export_type); + return EINA_FALSE; + } + + if (export_type == EXPORT_TYPE_FD) + close(seed); + + _shared_buffer_buffer_set(sb, buffer); + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_IMPORT); + + ecore_buffer_free_callback_add(buffer, _ecore_buffer_consumer_cb_buffer_free, consumer); + + return EINA_TRUE; +} diff --git a/src/lib/ecore_buffer/ecore_buffer_private.h b/src/lib/ecore_buffer/ecore_buffer_private.h new file mode 100644 index 0000000000..4e33772ed6 --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer_private.h @@ -0,0 +1,31 @@ +#ifndef _ECORE_BUFFER_PRIVATE_H_ +# define _ECORE_BUFFER_PRIVATE_H_ + +#ifdef ERR +#undef ERR +#endif +#ifdef WARN +#undef WARN +#endif +#ifdef DBG +#undef DBG +#endif + +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_buffer_queue_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_buffer_queue_log_dom, __VA_ARGS__) +#define WARN(...) EINA_LOG_DOM_WARN(_ecore_buffer_queue_log_dom, __VA_ARGS__) + +#define CALLBACK_CALL(obj, cbname) \ +do { \ + if (obj->cb.cbname) \ + obj->cb.cbname(obj, obj->cb.data); \ +} while(0) + +extern int _ecore_buffer_queue_log_dom; + +const char *_ecore_buffer_engine_name_get(Ecore_Buffer *buf); +/* NOTE: if Ecore_Export_Type as a return value is EXPORT_TYPE_FD, + * then caller should close the fd after using it. */ +Ecore_Export_Type _ecore_buffer_export(Ecore_Buffer *buf, int *id); +Ecore_Buffer *_ecore_buffer_import(const char *engine, int width, int height, Ecore_Buffer_Format format, Ecore_Export_Type type, int export_id, unsigned int flags); +#endif /* _ECORE_BUFFER_PRIVATE_H_ */ diff --git a/src/lib/ecore_buffer/ecore_buffer_provider.c b/src/lib/ecore_buffer/ecore_buffer_provider.c new file mode 100644 index 0000000000..53380fac84 --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer_provider.c @@ -0,0 +1,391 @@ +#include +#include + +#include +#include +#include + +#include "bq_mgr_protocol.h" +#include "shared_buffer.h" +#include "buffer_queue.h" +#include "ecore_buffer_private.h" +#include "ecore_buffer_con.h" + +struct _Ecore_Buffer_Provider +{ + struct bq_provider *resource; + Ecore_Buffer_Queue *ebq; + int free_slot; + struct + { + void (*consumer_add) (Ecore_Buffer_Provider *provider, int queue_size, int w, int h, void *data); + void (*consumer_del) (Ecore_Buffer_Provider *provider, void *data); + void (*enqueue) (Ecore_Buffer_Provider *provider, void *data); + void *data; + } cb; +}; + +static void _ecore_buffer_provider_cb_consumer_connected(void *data, struct bq_provider *bq_provider, int32_t queue_size, int32_t width, int32_t height); +static void _ecore_buffer_provider_cb_consumer_disconnected(void *data, struct bq_provider *bq_provider); +static void _ecore_buffer_provider_cb_add_buffer(void *data, struct bq_provider *bq_provider, struct bq_buffer *buffer, uint32_t serial); +static Shared_Buffer *_ecore_buffer_provider_shared_buffer_new(Ecore_Buffer_Provider *provider, Ecore_Buffer *buffer); +static void _ecore_buffer_provider_shared_buffer_free(Ecore_Buffer_Provider *provider, Shared_Buffer *sb); +static void _ecore_buffer_provider_cb_buffer_free(Ecore_Buffer *buf, void *data); + +struct bq_provider_listener _ecore_buffer_provider_listener = +{ + _ecore_buffer_provider_cb_consumer_connected, + _ecore_buffer_provider_cb_consumer_disconnected, + _ecore_buffer_provider_cb_add_buffer +}; + +EAPI Ecore_Buffer_Provider * +ecore_buffer_provider_new(const char *name) +{ + Ecore_Buffer_Provider *provider; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + DBG("Provider New - name %s", name); + + _ecore_buffer_con_init_wait(); + + provider = calloc(1, sizeof(Ecore_Buffer_Provider)); + if (!provider) + { + ERR("Failed to allocate Ecore_Buffer_Provider"); + return NULL; + } + + provider->resource = _ecore_buffer_con_provider_create(name); + if (!provider->resource) + { + ERR("Failed to get provider connection"); + free(provider); + return NULL; + } + + bq_provider_add_listener(provider->resource, &_ecore_buffer_provider_listener, provider); + bq_provider_set_user_data(provider->resource, provider); + + return provider; +} + +EAPI void +ecore_buffer_provider_free(Ecore_Buffer_Provider *provider) +{ + Eina_List *shared_buffers, *l; + Shared_Buffer *sb; + + EINA_SAFETY_ON_NULL_RETURN(provider); + + DBG("Provider Free"); + + if (provider->ebq) + { + shared_buffers = _ecore_buffer_queue_shared_buffer_list_get(provider->ebq); + EINA_LIST_FOREACH(shared_buffers, l, sb) + _ecore_buffer_provider_shared_buffer_free(provider, sb); + + _ecore_buffer_queue_free(provider->ebq); + } + + bq_provider_destroy(provider->resource); + free(provider); +} + +EAPI Ecore_Buffer_Return +ecore_buffer_provider_buffer_acquire(Ecore_Buffer_Provider *provider, Ecore_Buffer **ret_buf) +{ + Shared_Buffer *sb; + Ecore_Buffer_Return ret_flag = ECORE_BUFFER_RETURN_ERROR; + + EINA_SAFETY_ON_NULL_RETURN_VAL(provider, ret_flag); + + if (!provider->ebq) + return ret_flag; + + DBG("Buffer Acquire"); + + if (!_ecore_buffer_queue_dequeue(provider->ebq, &sb)) + { + ret_flag = ECORE_BUFFER_RETURN_EMPTY; + + // Check if exist free slot. + if (provider->free_slot > 0) + ret_flag = ECORE_BUFFER_RETURN_NEED_ALLOC; + } + else + { + // This should not happen. + if (_shared_buffer_state_get(sb) != SHARED_BUFFER_STATE_RELEASE) + { + ERR("Unknown error occured - Not on Released State: buffer %p state %s", + sb, _shared_buffer_state_string_get(sb)); + return ECORE_BUFFER_RETURN_ERROR; + } + + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_ACQUIRE); + + ret_flag = ECORE_BUFFER_RETURN_SUCCESS; + if (ret_buf) *ret_buf = _shared_buffer_buffer_get(sb); + } + + return ret_flag; +} + +EAPI Eina_Bool +ecore_buffer_provider_buffer_enqueue(Ecore_Buffer_Provider *provider, Ecore_Buffer *buffer) +{ + Shared_Buffer *sb; + Shared_Buffer_State state; + + EINA_SAFETY_ON_NULL_RETURN_VAL(provider, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(buffer, EINA_FALSE); + + DBG("Buffer Enqueue"); + + if (!provider->ebq) + { + WARN("Not connected with consumer yet."); + return EINA_FALSE; + } + + if (!(sb = _ecore_buffer_queue_shared_buffer_find(provider->ebq, buffer))) + { + // this buffer was never attached before. + if (provider->free_slot > 0) + { + sb = _ecore_buffer_provider_shared_buffer_new(provider, buffer); + if (!sb) + { + ERR("Unkown error occured -" + "Failed to attach buffer: buffer %p", buffer); + return EINA_FALSE; + } + provider->free_slot--; + } + else + { + WARN("No Free slot in Queue." + "Need to ecore_buffer_free of enqueueed buffer first."); + return EINA_FALSE; + } + } + + state = _shared_buffer_state_get(sb); + if ((state != SHARED_BUFFER_STATE_NEW) && + (state != SHARED_BUFFER_STATE_ACQUIRE)) + { + ERR("Failed to enqueue buffer - Not on acquired state: buffer %p state %s", + sb, _shared_buffer_state_string_get(sb)); + return EINA_FALSE; + } + + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_ENQUEUE); + bq_provider_enqueue_buffer(provider->resource, _shared_buffer_resource_get(sb), 0); + + return EINA_TRUE; +} + +EAPI Ecore_Buffer_Return +ecore_buffer_provider_buffer_acquirable_check(Ecore_Buffer_Provider *provider) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(provider, EINA_FALSE); + + if (_ecore_buffer_queue_is_empty(provider->ebq)) + { + if (provider->free_slot > 0) + return ECORE_BUFFER_RETURN_NEED_ALLOC; + + return ECORE_BUFFER_RETURN_EMPTY; + } + + return ECORE_BUFFER_RETURN_NOT_EMPTY; +} + +EAPI void +ecore_buffer_provider_consumer_add_cb_set(Ecore_Buffer_Provider *provider, Ecore_Buffer_Provider_Consumer_Add_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(provider); + + provider->cb.consumer_add = func; + provider->cb.data = data; +} + +EAPI void +ecore_buffer_provider_consumer_del_cb_set(Ecore_Buffer_Provider *provider, Ecore_Buffer_Provider_Consumer_Del_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(provider); + + provider->cb.consumer_del = func; + provider->cb.data = data; +} + +EAPI void +ecore_buffer_provider_buffer_released_cb_set(Ecore_Buffer_Provider *provider, Ecore_Buffer_Provider_Enqueue_Cb func, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(provider); + + provider->cb.enqueue = func; + provider->cb.data = data; +} + +static void +_ecore_buffer_provider_cb_consumer_connected(void *data, struct bq_provider *bq_provider EINA_UNUSED, int32_t queue_size, int32_t width, int32_t height) +{ + Ecore_Buffer_Provider *provider = data; + + EINA_SAFETY_ON_NULL_RETURN(provider); + + DBG("Consumer Connected - queue_size %d, size (%dx%d)", + queue_size, width, height); + + if (!(provider->ebq = _ecore_buffer_queue_new(width, height, queue_size))) + { + ERR("Failed to create Ecore_Buffer_Queue - queue_size %d, size (%dx%d)", + queue_size, width, height); + return; + } + + _ecore_buffer_queue_connection_state_set(provider->ebq, EINA_TRUE); + + // set the number of free slot which means allocatable buffer number. + provider->free_slot = queue_size; + + // CALLBACK_CALL + if (provider->cb.consumer_add) + provider->cb.consumer_add(provider, queue_size, width, height, provider->cb.data); +} + +static void +_ecore_buffer_provider_cb_consumer_disconnected(void *data, struct bq_provider *bq_provider EINA_UNUSED) +{ + Ecore_Buffer_Provider *provider = data; + + EINA_SAFETY_ON_NULL_RETURN(provider); + + DBG("Consumer Disconnected"); + + _ecore_buffer_queue_connection_state_set(provider->ebq, EINA_FALSE); + + _ecore_buffer_queue_free(provider->ebq); + provider->ebq = NULL; + + CALLBACK_CALL(provider, consumer_del); +} + +static void +_ecore_buffer_provider_cb_add_buffer(void *data, struct bq_provider *bq_provider EINA_UNUSED, struct bq_buffer *buffer, uint32_t serial EINA_UNUSED) +{ + Ecore_Buffer_Provider *provider = data; + Shared_Buffer *sb = bq_buffer_get_user_data(buffer); + + EINA_SAFETY_ON_NULL_RETURN(provider); + + if (!sb) return; + + DBG("Buffer Enqueued"); + + // Mark it as a released buffer. + _shared_buffer_state_set(sb, SHARED_BUFFER_STATE_RELEASE); + _ecore_buffer_queue_enqueue(provider->ebq, sb); + + CALLBACK_CALL(provider, enqueue); +} + +static void +_ecore_buffer_provider_cb_buffer_free(Ecore_Buffer *buffer, void *data) +{ + Ecore_Buffer_Provider *provider = data; + Shared_Buffer *sb = _ecore_buffer_queue_shared_buffer_find(provider->ebq, buffer); + + EINA_SAFETY_ON_NULL_RETURN(provider); + + if (!sb) return; + + _ecore_buffer_provider_shared_buffer_free(provider, sb); +} + +static Shared_Buffer * +_ecore_buffer_provider_shared_buffer_new(Ecore_Buffer_Provider *provider, Ecore_Buffer *buffer) +{ + Shared_Buffer *sb; + struct bq_buffer *buf_resource; + unsigned int w = 0, h = 0, format = 0; + Ecore_Export_Type export_type; + int export_id; + const char *engine; + unsigned int flags; + + EINA_SAFETY_ON_NULL_RETURN_VAL(provider, NULL); + + DBG("Create Shared Buffer - buffer %p", buffer); + + if (!provider->ebq) + { + WARN("Not connected with consumer yet."); + return NULL; + } + + ecore_buffer_size_get(buffer, &w, &h); + format = ecore_buffer_format_get(buffer); + export_type = _ecore_buffer_export(buffer, &export_id); + engine = _ecore_buffer_engine_name_get(buffer); + flags = ecore_buffer_flags_get(buffer); + + buf_resource = bq_provider_attach_buffer(provider->resource, engine, w, h, format, flags); + if (!buf_resource) + { + ERR("Fail to attach buffer - engine %s, size (%dx%d), format %d, flags %d", + engine, w, h, format, flags); + return NULL; + } + + switch (export_type) + { + case EXPORT_TYPE_ID: + bq_provider_set_buffer_id(provider->resource, buf_resource, + export_id, 0, 0, 0, 0, 0, 0); + break; + case EXPORT_TYPE_FD: + bq_provider_set_buffer_fd(provider->resource, buf_resource, + export_id, 0, 0, 0, 0, 0, 0); + close(export_id); + break; + default: + break; + } + + sb = _shared_buffer_new(engine, buf_resource, w, h, format, flags); + _shared_buffer_buffer_set(sb, buffer); + _ecore_buffer_queue_shared_buffer_add(provider->ebq, sb); + bq_buffer_set_user_data(buf_resource, sb); + + ecore_buffer_free_callback_add(buffer, _ecore_buffer_provider_cb_buffer_free, provider); + + return sb; +} + +static void +_ecore_buffer_provider_shared_buffer_free(Ecore_Buffer_Provider *provider, Shared_Buffer *sb) +{ + struct bq_buffer *buf_resource; + + EINA_SAFETY_ON_NULL_RETURN(provider); + EINA_SAFETY_ON_NULL_RETURN(sb); + + buf_resource = _shared_buffer_resource_get(sb); + if (!buf_resource) + return; + + DBG("Free Shared Buffer"); + + bq_provider_detach_buffer(provider->resource, buf_resource); + bq_buffer_destroy(buf_resource); + + _ecore_buffer_queue_shared_buffer_remove(provider->ebq, sb); + _shared_buffer_free(sb); + + provider->free_slot++; +} diff --git a/src/lib/ecore_buffer/ecore_buffer_queue_main.c b/src/lib/ecore_buffer/ecore_buffer_queue_main.c new file mode 100644 index 0000000000..a1883bb3fe --- /dev/null +++ b/src/lib/ecore_buffer/ecore_buffer_queue_main.c @@ -0,0 +1,54 @@ +#include +#include "ecore_buffer_private.h" +#include "ecore_buffer_con.h" + +int _ecore_buffer_queue_log_dom = -1; +static int _ecore_buffer_queue_init_count = 0; + +EAPI int +ecore_buffer_queue_init(void) +{ + if (++_ecore_buffer_queue_init_count != 1) + return _ecore_buffer_queue_init_count; + + _ecore_buffer_queue_log_dom = + eina_log_domain_register("ecore_buffer_queue", EINA_COLOR_GREEN); + + if (_ecore_buffer_queue_log_dom < 0) + { + EINA_LOG_ERR("Could not register log domain: ecore_buffer_queue"); + goto err; + } + +#ifdef DEBUG + eina_log_abort_on_critical_level_set(EINA_LOG_LEVEL_ERR); + eina_log_abort_on_critical_set(EINA_TRUE); +#endif + + DBG("Ecore_Buffer_Queue Init"); + + if (!_ecore_buffer_con_init()) + { + eina_log_domain_unregister(_ecore_buffer_queue_log_dom); + _ecore_buffer_queue_log_dom = -1; + goto err; + } + + return _ecore_buffer_queue_init_count; +err: + return --_ecore_buffer_queue_init_count; +} + +EAPI int +ecore_buffer_queue_shutdown(void) +{ + if (--_ecore_buffer_queue_init_count != 0) + return _ecore_buffer_queue_init_count; + + DBG("Ecore_Buffer_Queue Shutdown"); + _ecore_buffer_con_shutdown(); + eina_log_domain_unregister(_ecore_buffer_queue_log_dom); + _ecore_buffer_queue_log_dom = -1; + + return _ecore_buffer_queue_init_count; +} diff --git a/src/lib/ecore_buffer/shared_buffer.c b/src/lib/ecore_buffer/shared_buffer.c new file mode 100644 index 0000000000..82b4836b52 --- /dev/null +++ b/src/lib/ecore_buffer/shared_buffer.c @@ -0,0 +1,148 @@ +#include "shared_buffer.h" + +struct _Shared_Buffer +{ + Ecore_Buffer *buffer; + struct bq_buffer *resource; + const char *engine; + int w, h; + int format; + unsigned int flags; + Shared_Buffer_State state; +}; + +Shared_Buffer * +_shared_buffer_new(const char *engine, struct bq_buffer *resource, int w, int h, int format, unsigned int flags) +{ + Shared_Buffer *sb; + + sb = calloc(1, sizeof(Shared_Buffer)); + if (!sb) + return NULL; + + sb->engine = eina_stringshare_add(engine); + sb->resource = resource; + sb->w = w; + sb->h = h; + sb->format = format; + sb->flags = flags; + sb->state = SHARED_BUFFER_STATE_NEW; + + return sb; +} + +void +_shared_buffer_free(Shared_Buffer *sb) +{ + EINA_SAFETY_ON_NULL_RETURN(sb); + + if (sb->engine) eina_stringshare_del(sb->engine); + free(sb); +} + +Eina_Bool +_shared_buffer_info_get(Shared_Buffer *sb, const char **engine, int *w, int *h, int *format, unsigned int *flags) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, EINA_FALSE); + + if (engine) *engine = sb->engine; + if (w) *w = sb->w; + if (h) *h = sb->h; + if (format) *format = sb->format; + if (flags) *flags = sb->flags; + + return EINA_TRUE; +} + +Eina_Bool +_shared_buffer_buffer_set(Shared_Buffer *sb, Ecore_Buffer *buffer) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, EINA_FALSE); + + if (sb->buffer) + { + ERR("Already exist buffer"); + return EINA_FALSE; + } + + sb->buffer = buffer; + + return EINA_TRUE; +} + +Ecore_Buffer * +_shared_buffer_buffer_get(Shared_Buffer *sb) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, NULL); + + return sb->buffer; +} + +Eina_Bool +_shared_buffer_resource_set(Shared_Buffer *sb, struct bq_buffer *resource) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, EINA_FALSE); + + if (sb->resource) + { + ERR("Already exist resource"); + return EINA_FALSE; + } + + sb->resource = resource; + + return EINA_TRUE; +} + +struct bq_buffer * +_shared_buffer_resource_get(Shared_Buffer *sb) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, NULL); + + return sb->resource; +} + +void +_shared_buffer_state_set(Shared_Buffer *sb, Shared_Buffer_State state) +{ + EINA_SAFETY_ON_NULL_RETURN(sb); + + sb->state = state; +} + +Shared_Buffer_State +_shared_buffer_state_get(Shared_Buffer *sb) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, SHARED_BUFFER_STATE_UNKNOWN); + + return sb->state; +} + +const char * +_shared_buffer_state_string_get(Shared_Buffer *sb) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(sb, "INVAILD OBJECT"); + + switch (sb->state) + { + case SHARED_BUFFER_STATE_ENQUEUE: + return "SHARED_BUFFER_STATE_ENQUEUE"; + case SHARED_BUFFER_STATE_SUBMIT: + return "SHARED_BUFFER_STATE_SUBMIT"; + case SHARED_BUFFER_STATE_DEQUEUE: + return "SHARED_BUFFER_STATE_DEQUEUE"; + case SHARED_BUFFER_STATE_ATTACH: + return "SHARED_BUFFER_STATE_ATTACH"; + case SHARED_BUFFER_STATE_IMPORT: + return "SHARED_BUFFER_STATE_IMPORT"; + case SHARED_BUFFER_STATE_DETACH: + return "SHARED_BUFFER_STATE_DETACH"; + case SHARED_BUFFER_STATE_ACQUIRE: + return "SHARED_BUFFER_STATE_ACQUIRE"; + case SHARED_BUFFER_STATE_RELEASE: + return "SHARED_BUFFER_STATE_RELEASE"; + default: + case SHARED_BUFFER_STATE_UNKNOWN: + return "SHARED_BUFFER_STATE_UNKNOWN"; + } +} diff --git a/src/lib/ecore_buffer/shared_buffer.h b/src/lib/ecore_buffer/shared_buffer.h new file mode 100644 index 0000000000..ce168de3dd --- /dev/null +++ b/src/lib/ecore_buffer/shared_buffer.h @@ -0,0 +1,41 @@ +#ifndef _SHARED_BUFFER_H_ +# define _SHARED_BUFFER_H_ + +#include +#include +#include + +#include "bq_mgr_protocol.h" +#include "ecore_buffer_private.h" + +typedef struct _Shared_Buffer Shared_Buffer; + +typedef enum _Shared_Buffer_State +{ + // common + SHARED_BUFFER_STATE_UNKNOWN, + SHARED_BUFFER_STATE_ENQUEUE, + // provider side type + SHARED_BUFFER_STATE_NEW, + SHARED_BUFFER_STATE_SUBMIT, + SHARED_BUFFER_STATE_DEQUEUE, + // consumer side type + SHARED_BUFFER_STATE_ATTACH, + SHARED_BUFFER_STATE_IMPORT, + SHARED_BUFFER_STATE_DETACH, + SHARED_BUFFER_STATE_ACQUIRE, + SHARED_BUFFER_STATE_RELEASE, +} Shared_Buffer_State; + +Shared_Buffer *_shared_buffer_new(const char *engine, struct bq_buffer *resource, int w, int h, int format, unsigned int flags); +void _shared_buffer_free(Shared_Buffer *sb); +Eina_Bool _shared_buffer_info_get(Shared_Buffer *sb, const char **engine, int *w, int *h, int *format, unsigned int *flags); +Eina_Bool _shared_buffer_buffer_set(Shared_Buffer *sb, Ecore_Buffer *buffer); +Ecore_Buffer *_shared_buffer_buffer_get(Shared_Buffer *sb); +Eina_Bool _shared_buffer_resource_set(Shared_Buffer *sb, struct bq_buffer *resource); +struct bq_buffer *_shared_buffer_resource_get(Shared_Buffer *sb); +void _shared_buffer_state_set(Shared_Buffer *sb, Shared_Buffer_State state); +Shared_Buffer_State _shared_buffer_state_get(Shared_Buffer *sb); +const char *_shared_buffer_state_string_get(Shared_Buffer *sb); + +#endif /* _SHARED_BUFFER_H_ */ diff --git a/src/modules/ecore_buffer/shm/ecore_buffer_shm.c b/src/modules/ecore_buffer/shm/ecore_buffer_shm.c new file mode 100644 index 0000000000..75900ea094 --- /dev/null +++ b/src/modules/ecore_buffer/shm/ecore_buffer_shm.c @@ -0,0 +1,172 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#include +#include + +#include +#include +#include + +typedef struct _Ecore_Buffer_Shm_Data Ecore_Buffer_Shm_Data; + +struct _Ecore_Buffer_Shm_Data { + const char *file; + void *addr; + int w, h, stride, size; + Eina_Bool am_owner : 1; +}; + +static void +_ecore_buffer_shm_buffer_free(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_Shm_Data* b = bdata; + + if (b->am_owner) + if (b->file) unlink(b->file); + + if (b->addr != MAP_FAILED) munmap(b->addr, b->size); + eina_stringshare_del(b->file); + b->file = NULL; + b->addr = MAP_FAILED; + b->am_owner = EINA_FALSE; + b->w = 0; + b->h = 0; + b->stride = 0; + b->size = 0; + free(b); +} + + +static Ecore_Buffer_Data +_ecore_buffer_shm_buffer_alloc(Ecore_Buffer_Module_Data bmdata, int width, int height, Ecore_Buffer_Format format EINA_UNUSED, unsigned int flags EINA_UNUSED) +{ + Ecore_Buffer_Shm_Data* b; + char *name; + static const char tmp[] = "/ecore-buffer-shared-XXXXXX"; + const char *path; + int fd, size, page_size; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + path = getenv("TMPDIR"); + if (!path) path = "/tmp"; + } + + page_size = eina_cpu_page_size(); + + b = calloc(1, sizeof(Ecore_Buffer_Shm_Data)); + fd = -1; + b->addr = MAP_FAILED; + b->w = width; + b->h = height; + b->stride = width * sizeof(int); + b->size = page_size * (((b->stride * b->h) + (page_size - 1)) / page_size); + b->am_owner = EINA_TRUE; + + size = strlen(path) + sizeof(tmp); + name = malloc(size); + if (!name) goto err; + strcpy(name, path); + strcat(name, tmp); + + fd = mkostemp(name, O_CLOEXEC); + if (fd < 0) goto err_fd; + b->file = eina_stringshare_add(name); + free(name); + + if (ftruncate(fd, b->size) < 0) goto err; + + b->addr = mmap(NULL, b->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (b->addr == MAP_FAILED) goto err; + close(fd); + + return b; +err: + close(fd); +err_fd: + _ecore_buffer_shm_buffer_free(bmdata, b); + return NULL; +} + +static Ecore_Export_Type +_ecore_buffer_shm_buffer_export(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata, int *id) +{ + Ecore_Buffer_Shm_Data* b = bdata; + int fd; + + fd = open(b->file, O_RDWR | O_CLOEXEC); + if (id) *id = fd; + + return EXPORT_TYPE_FD; +} + +static void * +_ecore_buffer_shm_buffer_import(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, int w, int h, Ecore_Buffer_Format format EINA_UNUSED, Ecore_Export_Type type, int export_id, unsigned int flags EINA_UNUSED) +{ + Ecore_Buffer_Shm_Data* b; + int fd, page_size; + + EINA_SAFETY_ON_FALSE_RETURN_VAL(type == EXPORT_TYPE_FD, NULL); + + b = calloc(1, sizeof(Ecore_Buffer_Shm_Data)); + if (!b) return NULL; + + page_size = eina_cpu_page_size(); + + fd = export_id; + b->w = w; + b->h = h; + b->stride = w * sizeof(int); + b->size = page_size * (((b->stride * b->h) + (page_size - 1)) / page_size); + b->am_owner = EINA_FALSE; + + b->addr = mmap(NULL, b->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (b->addr == MAP_FAILED) goto err; + + return b; +err: + _ecore_buffer_shm_buffer_free(bmdata, b); + return NULL; +} + +static void * +_ecore_buffer_shm_data_get(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_Shm_Data *b = bdata; + + return b->addr; +} + +static Ecore_Buffer_Backend _ecore_buffer_shm_backend = { + "shm", + NULL, + NULL, + &_ecore_buffer_shm_buffer_alloc, + &_ecore_buffer_shm_buffer_free, + &_ecore_buffer_shm_buffer_export, + &_ecore_buffer_shm_buffer_import, + &_ecore_buffer_shm_data_get, + NULL, + NULL, +}; + +Eina_Bool shm_init(void) +{ + return ecore_buffer_register(&_ecore_buffer_shm_backend); +} + +void shm_shutdown(void) +{ + ecore_buffer_unregister(&_ecore_buffer_shm_backend); +} + +EINA_MODULE_INIT(shm_init); +EINA_MODULE_SHUTDOWN(shm_shutdown); diff --git a/src/modules/ecore_buffer/x11_dri2/ecore_buffer_x11_dri2.c b/src/modules/ecore_buffer/x11_dri2/ecore_buffer_x11_dri2.c new file mode 100644 index 0000000000..d673facd5a --- /dev/null +++ b/src/modules/ecore_buffer/x11_dri2/ecore_buffer_x11_dri2.c @@ -0,0 +1,538 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "Ecore_Buffer.h" +#include "ecore_buffer_private.h" + +typedef struct _Ecore_Buffer_Module_X11_Dri2_Data Ecore_Buffer_Module_X11_Dri2_Data; +typedef struct _Ecore_Buffer_X11_Dri2_Data Ecore_Buffer_X11_Dri2_Data; + +struct _Ecore_Buffer_Module_X11_Dri2_Data { + tbm_bufmgr tbm_mgr; +}; + +struct _Ecore_Buffer_X11_Dri2_Data { + Ecore_X_Pixmap pixmap; + int w; + int h; + int stride; + Ecore_Buffer_Format format; + Eina_Bool is_imported; + + struct + { + void *surface; + Eina_Bool owned; + } tbm; +}; + +static int +_buf_get_num_planes(Ecore_Buffer_Format format) +{ + int num_planes = 0; + + switch (format) + { + case ECORE_BUFFER_FORMAT_C8: + case ECORE_BUFFER_FORMAT_RGB332: + case ECORE_BUFFER_FORMAT_BGR233: + case ECORE_BUFFER_FORMAT_XRGB4444: + case ECORE_BUFFER_FORMAT_XBGR4444: + case ECORE_BUFFER_FORMAT_RGBX4444: + case ECORE_BUFFER_FORMAT_BGRX4444: + case ECORE_BUFFER_FORMAT_ARGB4444: + case ECORE_BUFFER_FORMAT_ABGR4444: + case ECORE_BUFFER_FORMAT_RGBA4444: + case ECORE_BUFFER_FORMAT_BGRA4444: + case ECORE_BUFFER_FORMAT_XRGB1555: + case ECORE_BUFFER_FORMAT_XBGR1555: + case ECORE_BUFFER_FORMAT_RGBX5551: + case ECORE_BUFFER_FORMAT_BGRX5551: + case ECORE_BUFFER_FORMAT_ARGB1555: + case ECORE_BUFFER_FORMAT_ABGR1555: + case ECORE_BUFFER_FORMAT_RGBA5551: + case ECORE_BUFFER_FORMAT_BGRA5551: + case ECORE_BUFFER_FORMAT_RGB565: + case ECORE_BUFFER_FORMAT_BGR565: + case ECORE_BUFFER_FORMAT_RGB888: + case ECORE_BUFFER_FORMAT_BGR888: + case ECORE_BUFFER_FORMAT_XRGB8888: + case ECORE_BUFFER_FORMAT_XBGR8888: + case ECORE_BUFFER_FORMAT_RGBX8888: + case ECORE_BUFFER_FORMAT_BGRX8888: + case ECORE_BUFFER_FORMAT_ARGB8888: + case ECORE_BUFFER_FORMAT_ABGR8888: + case ECORE_BUFFER_FORMAT_RGBA8888: + case ECORE_BUFFER_FORMAT_BGRA8888: + case ECORE_BUFFER_FORMAT_XRGB2101010: + case ECORE_BUFFER_FORMAT_XBGR2101010: + case ECORE_BUFFER_FORMAT_RGBX1010102: + case ECORE_BUFFER_FORMAT_BGRX1010102: + case ECORE_BUFFER_FORMAT_ARGB2101010: + case ECORE_BUFFER_FORMAT_ABGR2101010: + case ECORE_BUFFER_FORMAT_RGBA1010102: + case ECORE_BUFFER_FORMAT_BGRA1010102: + case ECORE_BUFFER_FORMAT_YUYV: + case ECORE_BUFFER_FORMAT_YVYU: + case ECORE_BUFFER_FORMAT_UYVY: + case ECORE_BUFFER_FORMAT_VYUY: + case ECORE_BUFFER_FORMAT_AYUV: + num_planes = 1; + break; + case ECORE_BUFFER_FORMAT_NV12: + case ECORE_BUFFER_FORMAT_NV21: + case ECORE_BUFFER_FORMAT_NV16: + case ECORE_BUFFER_FORMAT_NV61: + num_planes = 2; + break; + case ECORE_BUFFER_FORMAT_YUV410: + case ECORE_BUFFER_FORMAT_YVU410: + case ECORE_BUFFER_FORMAT_YUV411: + case ECORE_BUFFER_FORMAT_YVU411: + case ECORE_BUFFER_FORMAT_YUV420: + case ECORE_BUFFER_FORMAT_YVU420: + case ECORE_BUFFER_FORMAT_YUV422: + case ECORE_BUFFER_FORMAT_YVU422: + case ECORE_BUFFER_FORMAT_YUV444: + case ECORE_BUFFER_FORMAT_YVU444: + num_planes = 3; + break; + + default : + break; + } + + return num_planes; +} + +static int +_buf_get_bpp(Ecore_Buffer_Format format) +{ + int bpp = 0; + + switch (format) + { + case ECORE_BUFFER_FORMAT_C8: + case ECORE_BUFFER_FORMAT_RGB332: + case ECORE_BUFFER_FORMAT_BGR233: + bpp = 8; + break; + case ECORE_BUFFER_FORMAT_XRGB4444: + case ECORE_BUFFER_FORMAT_XBGR4444: + case ECORE_BUFFER_FORMAT_RGBX4444: + case ECORE_BUFFER_FORMAT_BGRX4444: + case ECORE_BUFFER_FORMAT_ARGB4444: + case ECORE_BUFFER_FORMAT_ABGR4444: + case ECORE_BUFFER_FORMAT_RGBA4444: + case ECORE_BUFFER_FORMAT_BGRA4444: + case ECORE_BUFFER_FORMAT_XRGB1555: + case ECORE_BUFFER_FORMAT_XBGR1555: + case ECORE_BUFFER_FORMAT_RGBX5551: + case ECORE_BUFFER_FORMAT_BGRX5551: + case ECORE_BUFFER_FORMAT_ARGB1555: + case ECORE_BUFFER_FORMAT_ABGR1555: + case ECORE_BUFFER_FORMAT_RGBA5551: + case ECORE_BUFFER_FORMAT_BGRA5551: + case ECORE_BUFFER_FORMAT_RGB565: + case ECORE_BUFFER_FORMAT_BGR565: + bpp = 16; + break; + case ECORE_BUFFER_FORMAT_RGB888: + case ECORE_BUFFER_FORMAT_BGR888: + bpp = 24; + break; + case ECORE_BUFFER_FORMAT_XRGB8888: + case ECORE_BUFFER_FORMAT_XBGR8888: + case ECORE_BUFFER_FORMAT_RGBX8888: + case ECORE_BUFFER_FORMAT_BGRX8888: + case ECORE_BUFFER_FORMAT_ARGB8888: + case ECORE_BUFFER_FORMAT_ABGR8888: + case ECORE_BUFFER_FORMAT_RGBA8888: + case ECORE_BUFFER_FORMAT_BGRA8888: + case ECORE_BUFFER_FORMAT_XRGB2101010: + case ECORE_BUFFER_FORMAT_XBGR2101010: + case ECORE_BUFFER_FORMAT_RGBX1010102: + case ECORE_BUFFER_FORMAT_BGRX1010102: + case ECORE_BUFFER_FORMAT_ARGB2101010: + case ECORE_BUFFER_FORMAT_ABGR2101010: + case ECORE_BUFFER_FORMAT_RGBA1010102: + case ECORE_BUFFER_FORMAT_BGRA1010102: + case ECORE_BUFFER_FORMAT_YUYV: + case ECORE_BUFFER_FORMAT_YVYU: + case ECORE_BUFFER_FORMAT_UYVY: + case ECORE_BUFFER_FORMAT_VYUY: + case ECORE_BUFFER_FORMAT_AYUV: + bpp = 32; + break; + case ECORE_BUFFER_FORMAT_NV12: + case ECORE_BUFFER_FORMAT_NV21: + bpp = 12; + break; + case ECORE_BUFFER_FORMAT_NV16: + case ECORE_BUFFER_FORMAT_NV61: + bpp = 16; + break; + case ECORE_BUFFER_FORMAT_YUV410: + case ECORE_BUFFER_FORMAT_YVU410: + bpp = 9; + break; + case ECORE_BUFFER_FORMAT_YUV411: + case ECORE_BUFFER_FORMAT_YVU411: + case ECORE_BUFFER_FORMAT_YUV420: + case ECORE_BUFFER_FORMAT_YVU420: + bpp = 12; + break; + case ECORE_BUFFER_FORMAT_YUV422: + case ECORE_BUFFER_FORMAT_YVU422: + bpp = 16; + break; + case ECORE_BUFFER_FORMAT_YUV444: + case ECORE_BUFFER_FORMAT_YVU444: + bpp = 24; + break; + default : + break; + } + + return bpp; +} + +static Ecore_Buffer_Module_Data +_ecore_buffer_x11_dri2_init(const char *context EINA_UNUSED, const char *options EINA_UNUSED) +{ + Ecore_X_Display *xdpy; + Ecore_X_Window root; + int eb, ee; + int major, minor; + char *driver_name; + char *device_name; + int fd = 0; + drm_magic_t magic; + Ecore_Buffer_Module_X11_Dri2_Data *mdata = NULL; + + if (!ecore_x_init(NULL)) + return NULL; + + xdpy = ecore_x_display_get(); + if (!xdpy) + goto on_error; + + root = ecore_x_window_root_first_get(); + if (!root) + goto on_error; + + mdata = calloc(1, sizeof(Ecore_Buffer_Module_X11_Dri2_Data)); + if (!mdata) + goto on_error; + + //Init DRI2 and TBM + DRI2QueryExtension(xdpy, &eb, &ee); + DRI2QueryVersion(xdpy, &major, &minor); + DRI2Connect(xdpy, root, &driver_name, &device_name); + + fd = open (device_name, O_RDWR); + if (fd < 0) + goto on_error; + + if (drmGetMagic(fd, &magic) < 0) + goto on_error; + + if (!(DRI2Authenticate(xdpy, root, magic))) + goto on_error; + + mdata->tbm_mgr = tbm_bufmgr_init(fd); + if (!mdata->tbm_mgr) + goto on_error; + + free(driver_name); + free(device_name); + close(fd); + + return mdata; + +on_error: + if (fd > 0) close(fd); + if (driver_name) free(driver_name); + if (device_name) free(device_name); + if (mdata) free(mdata); + ecore_x_shutdown(); + + return NULL; +} + +static void +_ecore_buffer_x11_dri2_shutdown(Ecore_Buffer_Module_Data bmdata) +{ + Ecore_Buffer_Module_X11_Dri2_Data *bm = bmdata; + + if (bm->tbm_mgr) + tbm_bufmgr_deinit(bm->tbm_mgr); + + ecore_x_shutdown(); +} + +static Ecore_Buffer_Data +_ecore_buffer_x11_dri2_buffer_alloc(Ecore_Buffer_Module_Data bmdata, int width, int height, Ecore_Buffer_Format format, unsigned int flags EINA_UNUSED) +{ + Ecore_X_Display *xdpy; + Ecore_X_Pixmap pixmap; + Ecore_Buffer_X11_Dri2_Data *buf; + Ecore_Buffer_Module_X11_Dri2_Data *bm = bmdata; + DRI2Buffer *bufs = NULL; + tbm_bo bo = NULL; + int bpp; + int num_plane; + int rw, rh, rcount; + unsigned int attachment = DRI2BufferFrontLeft; + tbm_surface_info_s info; + int i; + + bpp = _buf_get_bpp(format); + if (bpp != 32) + return NULL; + + num_plane = _buf_get_num_planes(format); + if (num_plane != 1) + return NULL; + + xdpy = ecore_x_display_get(); + pixmap = ecore_x_pixmap_new(0, width, height, bpp); + if (!pixmap) + return NULL; + + buf = calloc(1, sizeof(Ecore_Buffer_X11_Dri2_Data)); + if (!buf) + { + ecore_x_pixmap_free(pixmap); + return NULL; + } + + buf->w = width; + buf->h = height; + buf->format = format; + buf->pixmap = pixmap; + buf->is_imported = EINA_FALSE; + + //Get DRI2Buffer + DRI2CreateDrawable(xdpy, buf->pixmap); + bufs = DRI2GetBuffers(xdpy, buf->pixmap, &rw, &rh, &attachment, 1, &rcount); + if (!(bufs) || (buf->w != rw) || (buf->h != rh)) + goto on_error; + + buf->stride = bufs->pitch; + + //Import tbm_surface + bo = tbm_bo_import(bm->tbm_mgr, bufs->name); + if (!bo) + goto on_error; + + info.width = width; + info.height = height; + info.format = format; + info.bpp = bpp; + info.size = width * bufs->pitch; + for ( i = 0 ; i < num_plane ; i++) + { + info.planes[i].size = width * bufs->pitch; + info.planes[i].stride = bufs->pitch; + info.planes[i].offset = 0; + } + + buf->tbm.surface = tbm_surface_internal_create_with_bos(&info, &bo, 1); + if (!buf->tbm.surface) + goto on_error; + + buf->tbm.owned = EINA_TRUE; + tbm_bo_unref(bo); + free(bufs); + + return buf; + +on_error: + if (bo) tbm_bo_unref(bo); + if (bufs) free(bufs); + ecore_x_pixmap_free(buf->pixmap); + DRI2DestroyDrawable(xdpy, buf->pixmap); + free(buf); + + return NULL; +} + +static void +_ecore_buffer_x11_dri2_buffer_free(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_X11_Dri2_Data *buf = bdata; + + if (buf->pixmap) + { + DRI2DestroyDrawable(ecore_x_display_get(), buf->pixmap); + + if (!buf->is_imported) + ecore_x_pixmap_free(buf->pixmap); + } + + if (buf->tbm.surface) + tbm_surface_destroy(buf->tbm.surface); + + free(buf); + + return; +} + +static Ecore_Export_Type +_ecore_buffer_x11_dri2_buffer_export(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata, int *id) +{ + Ecore_Buffer_X11_Dri2_Data *buf = bdata; + + if (id) *id = buf->pixmap; + + return EXPORT_TYPE_ID; +} + +static void * +_ecore_buffer_x11_dri2_buffer_import(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, int w, int h, Ecore_Buffer_Format format, Ecore_Export_Type type, int export_id, unsigned int flags EINA_UNUSED) +{ + Ecore_Buffer_Module_X11_Dri2_Data *bm = bmdata; + Ecore_X_Display *xdpy; + Ecore_X_Pixmap pixmap = (Ecore_X_Pixmap)export_id; + Ecore_Buffer_X11_Dri2_Data *buf; + int rw, rh, rx, ry; + DRI2Buffer *bufs = NULL; + tbm_bo bo = NULL; + int rcount; + unsigned int attachment = DRI2BufferFrontLeft; + tbm_surface_info_s info; + int num_plane,i; + + if (type != EXPORT_TYPE_ID) + return NULL; + + xdpy = ecore_x_display_get(); + + //Check valid pixmap + ecore_x_pixmap_geometry_get(pixmap, &rx, &ry, &rw, &rh); + if ((rw != w) || (rh != h)) + return NULL; + + buf = calloc(1, sizeof(Ecore_Buffer_X11_Dri2_Data)); + if (!buf) + return NULL; + + buf->w = w; + buf->h = h; + buf->format = format; + buf->pixmap = pixmap; + buf->is_imported = EINA_TRUE; + + //Get DRI2Buffer + DRI2CreateDrawable(xdpy, buf->pixmap); + bufs = DRI2GetBuffers(xdpy, buf->pixmap, &rw, &rh, &attachment, 1, &rcount); + if ((!bufs) || (buf->w != rw) || (buf->h != rh)) + goto on_error; + + buf->stride = bufs->pitch; + + //Import tbm_surface + bo = tbm_bo_import(bm->tbm_mgr, bufs->name); + if (!bo) + goto on_error; + + num_plane = _buf_get_num_planes(format); + info.width = w; + info.height = h; + info.format = format; + info.bpp = _buf_get_bpp(format); + info.size = w * bufs->pitch; + for ( i = 0 ; i < num_plane ; i++) + { + info.planes[i].size = w * bufs->pitch; + info.planes[i].stride = bufs->pitch; + info.planes[i].offset = 0; + } + + buf->tbm.surface = tbm_surface_internal_create_with_bos(&info, &bo, 1); + if (!buf->tbm.surface) + goto on_error; + + buf->tbm.owned = EINA_TRUE; + tbm_bo_unref(bo); + free(bufs); + + return buf; +on_error: + if (bo) tbm_bo_unref(bo); + if (bufs) free(bufs); + DRI2DestroyDrawable(xdpy, buf->pixmap); + free(buf); + + return NULL; +} + +static Ecore_Pixmap +_ecore_buffer_x11_dri2_pixmap_get(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_X11_Dri2_Data *buf = bdata; + + if (!buf) + return 0; + + if (!buf->tbm.owned) + return 0; + + return buf->pixmap; +} + +static void * +_ecore_buffer_x11_dri2_tbm_bo_get(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_X11_Dri2_Data *buf = bdata; + + if (!buf) + return NULL; + + return buf->tbm.surface; +} + +static Ecore_Buffer_Backend _ecore_buffer_x11_dri2_backend = { + "x11_dri2", + &_ecore_buffer_x11_dri2_init, + &_ecore_buffer_x11_dri2_shutdown, + &_ecore_buffer_x11_dri2_buffer_alloc, + &_ecore_buffer_x11_dri2_buffer_free, + &_ecore_buffer_x11_dri2_buffer_export, + &_ecore_buffer_x11_dri2_buffer_import, + NULL, + &_ecore_buffer_x11_dri2_pixmap_get, + &_ecore_buffer_x11_dri2_tbm_bo_get, +}; + +Eina_Bool x11_dri2_init(void) +{ + return ecore_buffer_register(&_ecore_buffer_x11_dri2_backend); +} + +void x11_dri2_shutdown(void) +{ + ecore_buffer_unregister(&_ecore_buffer_x11_dri2_backend); +} + +EINA_MODULE_INIT(x11_dri2_init); +EINA_MODULE_SHUTDOWN(x11_dri2_shutdown); diff --git a/src/modules/ecore_buffer/x11_dri3/ecore_buffer_x11_dri3.c b/src/modules/ecore_buffer/x11_dri3/ecore_buffer_x11_dri3.c new file mode 100644 index 0000000000..d3ab7031df --- /dev/null +++ b/src/modules/ecore_buffer/x11_dri3/ecore_buffer_x11_dri3.c @@ -0,0 +1,602 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "ecore_buffer_private.h" + +typedef struct _Ecore_Buffer_Module_X11_Dri3_Data Ecore_Buffer_Module_X11_Dri3_Data; +typedef struct _Ecore_Buffer_X11_Dri3_Data Ecore_Buffer_X11_Dri3_Data; + +struct _Ecore_Buffer_Module_X11_Dri3_Data { + tbm_bufmgr tbm_mgr; +}; + +struct _Ecore_Buffer_X11_Dri3_Data { + Ecore_X_Pixmap pixmap; + void *tbm_surface; + int w; + int h; + int stride; + unsigned int flags; + Ecore_Buffer_Format format; + Eina_Bool is_imported; +}; + +static int +_buf_get_num_planes(Ecore_Buffer_Format format) +{ + int num_planes = 0; + + switch (format) + { + case ECORE_BUFFER_FORMAT_C8: + case ECORE_BUFFER_FORMAT_RGB332: + case ECORE_BUFFER_FORMAT_BGR233: + case ECORE_BUFFER_FORMAT_XRGB4444: + case ECORE_BUFFER_FORMAT_XBGR4444: + case ECORE_BUFFER_FORMAT_RGBX4444: + case ECORE_BUFFER_FORMAT_BGRX4444: + case ECORE_BUFFER_FORMAT_ARGB4444: + case ECORE_BUFFER_FORMAT_ABGR4444: + case ECORE_BUFFER_FORMAT_RGBA4444: + case ECORE_BUFFER_FORMAT_BGRA4444: + case ECORE_BUFFER_FORMAT_XRGB1555: + case ECORE_BUFFER_FORMAT_XBGR1555: + case ECORE_BUFFER_FORMAT_RGBX5551: + case ECORE_BUFFER_FORMAT_BGRX5551: + case ECORE_BUFFER_FORMAT_ARGB1555: + case ECORE_BUFFER_FORMAT_ABGR1555: + case ECORE_BUFFER_FORMAT_RGBA5551: + case ECORE_BUFFER_FORMAT_BGRA5551: + case ECORE_BUFFER_FORMAT_RGB565: + case ECORE_BUFFER_FORMAT_BGR565: + case ECORE_BUFFER_FORMAT_RGB888: + case ECORE_BUFFER_FORMAT_BGR888: + case ECORE_BUFFER_FORMAT_XRGB8888: + case ECORE_BUFFER_FORMAT_XBGR8888: + case ECORE_BUFFER_FORMAT_RGBX8888: + case ECORE_BUFFER_FORMAT_BGRX8888: + case ECORE_BUFFER_FORMAT_ARGB8888: + case ECORE_BUFFER_FORMAT_ABGR8888: + case ECORE_BUFFER_FORMAT_RGBA8888: + case ECORE_BUFFER_FORMAT_BGRA8888: + case ECORE_BUFFER_FORMAT_XRGB2101010: + case ECORE_BUFFER_FORMAT_XBGR2101010: + case ECORE_BUFFER_FORMAT_RGBX1010102: + case ECORE_BUFFER_FORMAT_BGRX1010102: + case ECORE_BUFFER_FORMAT_ARGB2101010: + case ECORE_BUFFER_FORMAT_ABGR2101010: + case ECORE_BUFFER_FORMAT_RGBA1010102: + case ECORE_BUFFER_FORMAT_BGRA1010102: + case ECORE_BUFFER_FORMAT_YUYV: + case ECORE_BUFFER_FORMAT_YVYU: + case ECORE_BUFFER_FORMAT_UYVY: + case ECORE_BUFFER_FORMAT_VYUY: + case ECORE_BUFFER_FORMAT_AYUV: + num_planes = 1; + break; + case ECORE_BUFFER_FORMAT_NV12: + case ECORE_BUFFER_FORMAT_NV21: + case ECORE_BUFFER_FORMAT_NV16: + case ECORE_BUFFER_FORMAT_NV61: + num_planes = 2; + break; + case ECORE_BUFFER_FORMAT_YUV410: + case ECORE_BUFFER_FORMAT_YVU410: + case ECORE_BUFFER_FORMAT_YUV411: + case ECORE_BUFFER_FORMAT_YVU411: + case ECORE_BUFFER_FORMAT_YUV420: + case ECORE_BUFFER_FORMAT_YVU420: + case ECORE_BUFFER_FORMAT_YUV422: + case ECORE_BUFFER_FORMAT_YVU422: + case ECORE_BUFFER_FORMAT_YUV444: + case ECORE_BUFFER_FORMAT_YVU444: + num_planes = 3; + break; + + default : + break; + } + + return num_planes; +} + +static int +_buf_get_bpp(Ecore_Buffer_Format format) +{ + int bpp = 0; + + switch (format) + { + case ECORE_BUFFER_FORMAT_C8: + case ECORE_BUFFER_FORMAT_RGB332: + case ECORE_BUFFER_FORMAT_BGR233: + bpp = 8; + break; + case ECORE_BUFFER_FORMAT_XRGB4444: + case ECORE_BUFFER_FORMAT_XBGR4444: + case ECORE_BUFFER_FORMAT_RGBX4444: + case ECORE_BUFFER_FORMAT_BGRX4444: + case ECORE_BUFFER_FORMAT_ARGB4444: + case ECORE_BUFFER_FORMAT_ABGR4444: + case ECORE_BUFFER_FORMAT_RGBA4444: + case ECORE_BUFFER_FORMAT_BGRA4444: + case ECORE_BUFFER_FORMAT_XRGB1555: + case ECORE_BUFFER_FORMAT_XBGR1555: + case ECORE_BUFFER_FORMAT_RGBX5551: + case ECORE_BUFFER_FORMAT_BGRX5551: + case ECORE_BUFFER_FORMAT_ARGB1555: + case ECORE_BUFFER_FORMAT_ABGR1555: + case ECORE_BUFFER_FORMAT_RGBA5551: + case ECORE_BUFFER_FORMAT_BGRA5551: + case ECORE_BUFFER_FORMAT_RGB565: + case ECORE_BUFFER_FORMAT_BGR565: + bpp = 16; + break; + case ECORE_BUFFER_FORMAT_RGB888: + case ECORE_BUFFER_FORMAT_BGR888: + bpp = 24; + break; + case ECORE_BUFFER_FORMAT_XRGB8888: + case ECORE_BUFFER_FORMAT_XBGR8888: + case ECORE_BUFFER_FORMAT_RGBX8888: + case ECORE_BUFFER_FORMAT_BGRX8888: + case ECORE_BUFFER_FORMAT_ARGB8888: + case ECORE_BUFFER_FORMAT_ABGR8888: + case ECORE_BUFFER_FORMAT_RGBA8888: + case ECORE_BUFFER_FORMAT_BGRA8888: + case ECORE_BUFFER_FORMAT_XRGB2101010: + case ECORE_BUFFER_FORMAT_XBGR2101010: + case ECORE_BUFFER_FORMAT_RGBX1010102: + case ECORE_BUFFER_FORMAT_BGRX1010102: + case ECORE_BUFFER_FORMAT_ARGB2101010: + case ECORE_BUFFER_FORMAT_ABGR2101010: + case ECORE_BUFFER_FORMAT_RGBA1010102: + case ECORE_BUFFER_FORMAT_BGRA1010102: + case ECORE_BUFFER_FORMAT_YUYV: + case ECORE_BUFFER_FORMAT_YVYU: + case ECORE_BUFFER_FORMAT_UYVY: + case ECORE_BUFFER_FORMAT_VYUY: + case ECORE_BUFFER_FORMAT_AYUV: + bpp = 32; + break; + case ECORE_BUFFER_FORMAT_NV12: + case ECORE_BUFFER_FORMAT_NV21: + bpp = 12; + break; + case ECORE_BUFFER_FORMAT_NV16: + case ECORE_BUFFER_FORMAT_NV61: + bpp = 16; + break; + case ECORE_BUFFER_FORMAT_YUV410: + case ECORE_BUFFER_FORMAT_YVU410: + bpp = 9; + break; + case ECORE_BUFFER_FORMAT_YUV411: + case ECORE_BUFFER_FORMAT_YVU411: + case ECORE_BUFFER_FORMAT_YUV420: + case ECORE_BUFFER_FORMAT_YVU420: + bpp = 12; + break; + case ECORE_BUFFER_FORMAT_YUV422: + case ECORE_BUFFER_FORMAT_YVU422: + bpp = 16; + break; + case ECORE_BUFFER_FORMAT_YUV444: + case ECORE_BUFFER_FORMAT_YVU444: + bpp = 24; + break; + default : + break; + } + + return bpp; +} + +static int +_buf_get_depth(Ecore_Buffer_Format format) +{ + int depth = 0; + + switch (format) + { + case ECORE_BUFFER_FORMAT_C8: + case ECORE_BUFFER_FORMAT_RGB332: + case ECORE_BUFFER_FORMAT_BGR233: + depth = 8; + break; + case ECORE_BUFFER_FORMAT_XRGB4444: + case ECORE_BUFFER_FORMAT_XBGR4444: + case ECORE_BUFFER_FORMAT_RGBX4444: + case ECORE_BUFFER_FORMAT_BGRX4444: + depth = 12; + break; + case ECORE_BUFFER_FORMAT_ARGB4444: + case ECORE_BUFFER_FORMAT_ABGR4444: + case ECORE_BUFFER_FORMAT_RGBA4444: + case ECORE_BUFFER_FORMAT_BGRA4444: + depth = 16; + break; + case ECORE_BUFFER_FORMAT_XRGB1555: + case ECORE_BUFFER_FORMAT_XBGR1555: + case ECORE_BUFFER_FORMAT_RGBX5551: + case ECORE_BUFFER_FORMAT_BGRX5551: + depth = 15; + break; + case ECORE_BUFFER_FORMAT_ARGB1555: + case ECORE_BUFFER_FORMAT_ABGR1555: + case ECORE_BUFFER_FORMAT_RGBA5551: + case ECORE_BUFFER_FORMAT_BGRA5551: + case ECORE_BUFFER_FORMAT_RGB565: + case ECORE_BUFFER_FORMAT_BGR565: + depth = 16; + break; + case ECORE_BUFFER_FORMAT_RGB888: + case ECORE_BUFFER_FORMAT_BGR888: + depth = 24; + break; + case ECORE_BUFFER_FORMAT_XRGB8888: + case ECORE_BUFFER_FORMAT_XBGR8888: + case ECORE_BUFFER_FORMAT_RGBX8888: + case ECORE_BUFFER_FORMAT_BGRX8888: + depth = 24; + break; + case ECORE_BUFFER_FORMAT_ARGB8888: + case ECORE_BUFFER_FORMAT_ABGR8888: + case ECORE_BUFFER_FORMAT_RGBA8888: + case ECORE_BUFFER_FORMAT_BGRA8888: + depth = 32; + break; + case ECORE_BUFFER_FORMAT_XRGB2101010: + case ECORE_BUFFER_FORMAT_XBGR2101010: + case ECORE_BUFFER_FORMAT_RGBX1010102: + case ECORE_BUFFER_FORMAT_BGRX1010102: + depth = 30; + break; + case ECORE_BUFFER_FORMAT_ARGB2101010: + case ECORE_BUFFER_FORMAT_ABGR2101010: + case ECORE_BUFFER_FORMAT_RGBA1010102: + case ECORE_BUFFER_FORMAT_BGRA1010102: + depth = 32; + break; + case ECORE_BUFFER_FORMAT_YUYV: + case ECORE_BUFFER_FORMAT_YVYU: + case ECORE_BUFFER_FORMAT_UYVY: + case ECORE_BUFFER_FORMAT_VYUY: + case ECORE_BUFFER_FORMAT_AYUV: + case ECORE_BUFFER_FORMAT_NV12: + case ECORE_BUFFER_FORMAT_NV21: + case ECORE_BUFFER_FORMAT_NV16: + case ECORE_BUFFER_FORMAT_NV61: + case ECORE_BUFFER_FORMAT_YUV410: + case ECORE_BUFFER_FORMAT_YVU410: + case ECORE_BUFFER_FORMAT_YUV411: + case ECORE_BUFFER_FORMAT_YVU411: + case ECORE_BUFFER_FORMAT_YUV420: + case ECORE_BUFFER_FORMAT_YVU420: + case ECORE_BUFFER_FORMAT_YUV422: + case ECORE_BUFFER_FORMAT_YVU422: + case ECORE_BUFFER_FORMAT_YUV444: + case ECORE_BUFFER_FORMAT_YVU444: + default : + depth = 0; //unknown in X + break; + } + + return depth; +} + +static int +_dri3_open(Ecore_X_Display *dpy, Ecore_X_Window root, unsigned provider) +{ + xcb_connection_t *c = XGetXCBConnection(dpy); + xcb_dri3_open_cookie_t cookie; + xcb_dri3_open_reply_t *reply; + + cookie = xcb_dri3_open(c, root, provider); + reply = xcb_dri3_open_reply(c, cookie, NULL); + if ((!reply) || (reply->nfd != 1)) + return -1; + + return xcb_dri3_open_reply_fds(c, reply)[0]; +} + +static Ecore_X_Pixmap +_dri3_pixmap_from_fd(Ecore_X_Display *dpy, Ecore_X_Drawable draw, int width, int height, int depth, int fd, int bpp, int stride, int size) +{ + xcb_connection_t *c = XGetXCBConnection(dpy); + Ecore_X_Pixmap pixmap = xcb_generate_id(c); + + if (!dpy) + return 0; + + c = XGetXCBConnection(dpy); + if (!c) + return 0; + + pixmap = xcb_generate_id(c); + if (!pixmap) + return 0; + + xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd); + + return pixmap; +} + +static Ecore_Buffer_Module_Data +_ecore_buffer_x11_dri3_init(const char *context EINA_UNUSED, const char *options EINA_UNUSED) +{ + Ecore_X_Display *xdpy; + Ecore_X_Window root; + Ecore_Buffer_Module_X11_Dri3_Data *mdata = NULL; + int fd = 0; + + if (!ecore_x_init(NULL)) + return NULL; + + xdpy = ecore_x_display_get(); + if (!xdpy) + goto on_error; + + root = ecore_x_window_root_first_get(); + if (!root) + goto on_error; + + mdata = calloc(1, sizeof(Ecore_Buffer_Module_X11_Dri3_Data)); + if (!mdata) + goto on_error; + + //Init DRI3 and TBM + fd = _dri3_open(xdpy, root, 0); + if (fd < 0) + goto on_error; + + mdata->tbm_mgr = tbm_bufmgr_init(fd); + if (!mdata->tbm_mgr) + goto on_error; + + close(fd); + + return mdata; + +on_error: + if (fd > 0) close(fd); + if (mdata) free(mdata); + ecore_x_shutdown(); + + return NULL; +} + +static void +_ecore_buffer_x11_dri3_shutdown(Ecore_Buffer_Module_Data bmdata) +{ + Ecore_Buffer_Module_X11_Dri3_Data *bm = bmdata; + + if (!bm) + return; + + if (bm->tbm_mgr) + tbm_bufmgr_deinit(bm->tbm_mgr); + + ecore_x_shutdown(); +} + +static Ecore_Buffer_Data +_ecore_buffer_x11_dri3_buffer_alloc(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, int width, int height, Ecore_Buffer_Format format, unsigned int flags) +{ + Ecore_Buffer_X11_Dri3_Data *buf; + + buf = calloc(1, sizeof(Ecore_Buffer_X11_Dri3_Data)); + if (!buf) + return NULL; + + buf->w = width; + buf->h = height; + buf->format = format; + buf->flags = flags; + buf->is_imported = EINA_FALSE; + buf->tbm_surface = tbm_surface_create(width,height,(tbm_format)format); + if (!buf->tbm_surface) + { + free(buf); + return NULL; + } + + return buf; +} + +static Ecore_Buffer_Data +static void +_ecore_buffer_x11_dri3_buffer_free(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_X11_Dri3_Data *buf = bdata; + + if (!buf) + return; + + if (buf->pixmap) + ecore_x_pixmap_free(buf->pixmap); + + if (buf->tbm_surface) + tbm_surface_destroy(buf->tbm_surface); + + free(buf); +} + +static Ecore_Export_Type +_ecore_buffer_x11_dri3_buffer_export(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata, int *id) +{ + Ecore_Buffer_X11_Dri3_Data *buf = bdata; + tbm_bo bo; + + if (_buf_get_num_planes(buf->format) != 1) + return EXPORT_TYPE_INVALID; + + bo = tbm_surface_internal_get_bo(buf->tbm_surface, 0); + if (!bo) + return EXPORT_TYPE_INVALID; + + if (id) *id = tbm_bo_export_fd(bo); + + return EXPORT_TYPE_FD; +} + +static Ecore_Buffer_Data +_ecore_buffer_x11_dri3_buffer_import(Ecore_Buffer_Module_Data bmdata, int w, int h, Ecore_Buffer_Format format, Ecore_Export_Type type, int export_id, unsigned int flags) +{ + Ecore_Buffer_Module_X11_Dri3_Data *bm = bmdata; + Ecore_Buffer_X11_Dri3_Data *buf; + tbm_bo bo; + tbm_surface_info_s info; + int i, num_plane; + + if (!bm) + return NULL; + + if (type != EXPORT_TYPE_FD) + return NULL; + + if (export_id < 1) + return NULL; + + buf = calloc(1, sizeof(Ecore_Buffer_X11_Dri3_Data)); + if (!buf) + return NULL; + + buf->w = w; + buf->h = h; + buf->format = format; + buf->flags = flags; + buf->is_imported = EINA_TRUE; + + //Import tbm_surface + bo = tbm_bo_import_fd(bm->tbm_mgr, export_id); + if (!bo) + { + free(buf); + return NULL; + } + + num_plane = _buf_get_num_planes(format); + info.width = w; + info.height = h; + info.format = format; + info.bpp = _buf_get_bpp(format); + info.size = w * h * info.bpp; + for ( i = 0 ; i < num_plane ; i++) + { + info.planes[i].size = w * h * info.bpp; + info.planes[i].stride = w * info.bpp; + info.planes[i].offset = 0; + } + + buf->tbm_surface = tbm_surface_internal_create_with_bos(&info, &bo, 1); + if (!buf->tbm_surface) + { + tbm_bo_unref(bo); + free(buf); + return NULL; + } + + tbm_bo_unref(bo); + + return buf; +} + +static Ecore_Pixmap +_ecore_buffer_x11_dri3_pixmap_get(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_X11_Dri3_Data *buf = bdata; + Ecore_X_Display *xdpy; + Ecore_X_Window root; + tbm_surface_info_s info; + tbm_bo bo; + int ret; + + if (!buf) + return 0; + + if (buf->pixmap) + return buf->pixmap; + + ret = tbm_surface_get_info(buf->tbm_surface, &info); + if (ret != 0) + return 0; + + if (info.num_planes != 1) + return 0; + + bo = tbm_surface_internal_get_bo(buf->tbm_surface, 0); + if (!bo) + return 0; + + xdpy = ecore_x_display_get(); + root = ecore_x_window_root_first_get(); + buf->pixmap = _dri3_pixmap_from_fd(xdpy, root, + buf->w, buf->h, + _buf_get_depth(buf->format), + tbm_bo_export_fd(bo), + _buf_get_bpp(buf->format), + info.planes[0].stride, + info.planes[0].size); + + return buf->pixmap; +} + +static void * +_ecore_buffer_x11_dri3_tbm_bo_get(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata) +{ + Ecore_Buffer_X11_Dri3_Data *buf = bdata; + + if (!buf) + return NULL; + + return buf->tbm_surface; +} + +static Ecore_Buffer_Backend _ecore_buffer_x11_dri3_backend = { + "x11_dri3", + &_ecore_buffer_x11_dri3_init, + &_ecore_buffer_x11_dri3_shutdown, + &_ecore_buffer_x11_dri3_buffer_alloc, + &_ecore_buffer_x11_dri3_buffer_free, + &_ecore_buffer_x11_dri3_buffer_export, + &_ecore_buffer_x11_dri3_buffer_import, + NULL, + &_ecore_buffer_x11_dri3_pixmap_get, + &_ecore_buffer_x11_dri3_tbm_bo_get, +}; + +Eina_Bool x11_dri3_init(void) +{ + return ecore_buffer_register(&_ecore_buffer_x11_dri3_backend); +} + +void x11_dri3_shutdown(void) +{ + ecore_buffer_unregister(&_ecore_buffer_x11_dri3_backend); +} + +EINA_MODULE_INIT(x11_dri3_init); +EINA_MODULE_SHUTDOWN(x11_dri3_shutdown);