--- /dev/null
+#include "e_video_internal.h"
+
+#include <tizen-extension-server-protocol.h>
+
+#ifdef EO_DATA_KEY
+#undef EO_DATA_KEY
+#endif
+#define EO_DATA_KEY "E_Client_Video_Surface_Provider"
+
+#ifdef INTERN_DATA_GET
+#undef INTERN_DATA_GET
+#endif
+#define INTERN_DATA_GET \
+ E_Client_Video_Surface_Provider *pd; \
+ pd = evas_object_data_get(ec->frame, EO_DATA_KEY)
+
+#ifdef MY_HANDLE
+#undef MY_HANDLE
+#endif
+#define MY_HANDLE E_Client_Video_Surface_Provider
+
+struct _E_Client_Video_Surface_Provider
+{
+ E_Client *ec;
+
+ Eina_List *event_handlers;
+
+ struct
+ {
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+ } wl;
+
+ struct
+ {
+ struct
+ {
+ E_Comp_Wl_Surface_State data;
+ E_Comp_Wl_Buffer_Ref buffer_ref;
+ } cache;
+
+ int video_count;
+ uint32_t serial;
+
+ Eina_Bool pending_enabled;
+ Eina_Bool enabled;
+ Eina_Bool done;
+ } sync;
+};
+
+static Eina_Bool _ecvsp_ec_validate(E_Client *ec);
+static MY_HANDLE *_ecvsp_create(E_Client *ec, struct wl_resource *wl_resource);
+static void _ecvsp_destroy(MY_HANDLE *pd);
+static void _ecvsp_commit_to_cache(MY_HANDLE *pd, E_Comp_Wl_Surface_State *src);
+static void _ecvsp_commit_from_cache(MY_HANDLE *pd);
+static void _ecvsp_commit(MY_HANDLE *pd);
+static Eina_Bool _ecvsp_sync_done_check(MY_HANDLE *pd);
+
+static Eina_Bool _ecvsp_cb_ec_remove(void *data, int type, void *event);
+
+E_API Eina_Bool
+e_client_video_surface_provider_set(E_Client *ec, struct wl_resource *wl_resource)
+{
+ MY_HANDLE *pd;
+
+ VIN("Set video surface provider", ec);
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wl_resource, EINA_FALSE);
+
+ if (!_ecvsp_ec_validate(ec))
+ {
+ VER("validation failed", ec);
+ return EINA_FALSE;
+ }
+
+ pd = evas_object_data_get(ec->frame, EO_DATA_KEY);
+ if (pd)
+ {
+ VER("Given client was already set as Video Surface Provider", ec);
+ /* FIXME TRUE? FALSE? */
+ return EINA_FALSE;
+ }
+
+ pd = _ecvsp_create(ec, wl_resource);
+ if (!pd)
+ {
+ VER("failed to create Video Surface Provider", ec);
+ return EINA_FALSE;
+ }
+
+ evas_object_data_set(ec->frame, EO_DATA_KEY, pd);
+
+ return EINA_TRUE;
+}
+
+E_API void
+e_client_video_surface_provider_unset(E_Client *ec)
+{
+ INTERN_DATA_GET;
+
+ if (!pd)
+ {
+ VWR("It's not video client or already deleted(%d)",
+ ec, e_object_is_del(E_OBJECT(ec)));
+ return;
+ }
+
+ VIN("Unset video surface provider", ec);
+
+ evas_object_data_del(ec->frame, EO_DATA_KEY);
+
+ _ecvsp_destroy(pd);
+}
+
+E_API Eina_Bool
+e_client_video_surface_provider_check(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ INTERN_DATA_GET;
+
+ return !!pd;
+}
+
+EINTERN Eina_Bool
+e_client_video_surface_provider_sync_done_check(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
+
+ INTERN_DATA_GET;
+
+ if (!pd->sync.enabled)
+ return EINA_FALSE;
+
+ return _ecvsp_sync_done_check(pd);
+}
+
+/* NOTE
+ * e_comp_wl_surface_commit() will be done if it returns false.
+ * So, note that you have to call e_comp_wl_surface_commit() somewhere if
+ * you want revise this behavior. */
+EINTERN Eina_Bool
+e_client_video_surface_provider_commit(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->comp_data, EINA_FALSE);
+
+ INTERN_DATA_GET;
+
+ if (!pd)
+ return EINA_FALSE;
+
+ if ((pd->sync.enabled) &&
+ (!pd->sync.pending_enabled))
+ {
+ /* FIXME consider again */
+ VIN("dislabed sync before done", ec);
+ goto sync_done;
+ }
+
+ pd->sync.enabled = pd->sync.pending_enabled;
+ pd->sync.pending_enabled = EINA_FALSE;
+
+ if (!pd->sync.enabled)
+ return EINA_FALSE;
+
+ if (_ecvsp_sync_done_check(pd))
+ goto sync_done;
+ else
+ _ecvsp_commit_to_cache(pd, &ec->comp_data->pending);
+
+ return EINA_TRUE;
+
+sync_done:
+ VIN("sync done: serial(%d)", ec, pd->sync.serial);
+
+ _ecvsp_commit(pd);
+
+ return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_client_video_surface_provider_commit_by_sync(E_Client *ec)
+{
+ E_Client *subc;
+ Eina_List *l;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->comp_data, EINA_FALSE);
+
+ INTERN_DATA_GET;
+
+ if (!pd)
+ return EINA_FALSE;
+
+ if (!pd->sync.enabled)
+ return EINA_FALSE;
+
+ VIN("sync done: serial(%d)", ec, pd->sync.serial);
+
+ if (pd->sync.cache.data.has_data)
+ _ecvsp_commit_from_cache(pd);
+
+ EINA_LIST_FOREACH(pd->ec->comp_data->sub.list, l, subc)
+ {
+ if (pd->ec != subc)
+ e_comp_wl_subsurface_parent_commit(subc, EINA_FALSE);
+ }
+
+ EINA_LIST_FOREACH(pd->ec->comp_data->sub.below_list, l, subc)
+ {
+ if (pd->ec != subc)
+ e_comp_wl_subsurface_parent_commit(subc, EINA_FALSE);
+ }
+
+ /* notify sync done to wl_client */
+ tizen_video_surface_provider_send_sync_done(pd->wl.resource,
+ pd->sync.serial);
+
+ pd->sync.enabled = EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecvsp_ec_validate(E_Client *ec)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->comp_data, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
+
+ if (e_object_is_del(E_OBJECT(ec)))
+ {
+ VER("Can't handle deleted client", ec);
+ return EINA_FALSE;
+ }
+
+ if (e_client_is_video(ec))
+ {
+ VER("Video Client cannot be Video Surface Provider", ec);
+ return EINA_FALSE;
+ }
+
+ if (ec->comp_data->sub.data)
+ {
+ VER("Subsurface is not supported for Vide Surface Provider for now", ec);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecvsp_cb_ec_remove(void *data, int type, void *event)
+{
+ E_Event_Client *ev;
+ MY_HANDLE *pd;
+
+ ev = event;
+ pd = data;
+
+ if (ev->ec != pd->ec)
+ goto end;
+
+ _ecvsp_destroy(pd);
+
+end:
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_ecvsp_cb_wl_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+_ecvsp_cb_wl_sync_serial_set(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
+{
+ MY_HANDLE *pd;
+
+ pd = wl_resource_get_user_data(resource);
+
+ VIN("sync with serial (%d)", pd->ec, serial);
+
+ pd->sync.serial = serial;
+ pd->sync.pending_enabled = EINA_TRUE;
+}
+
+static const struct tizen_video_surface_provider_interface _ecvsp_wl_interface =
+{
+ _ecvsp_cb_wl_destroy,
+ _ecvsp_cb_wl_sync_serial_set,
+};
+
+static void
+_ecvsp_cb_wl_resource_destroy(struct wl_resource *resource)
+{
+ MY_HANDLE *pd;
+
+ pd = wl_resource_get_user_data(resource);
+
+ _ecvsp_destroy(pd);
+}
+
+static MY_HANDLE *
+_ecvsp_create(E_Client *ec, struct wl_resource *wl_resource)
+{
+ MY_HANDLE *pd;
+
+ pd = E_NEW(MY_HANDLE, 1);
+ if (!pd)
+ {
+ VER("Failed to allocate memory", ec);
+ return EINA_FALSE;
+ }
+
+ e_object_ref(E_OBJECT(ec));
+
+ pd->ec = ec;
+ pd->wl.resource = wl_resource;
+
+ wl_resource_set_implementation(wl_resource,
+ &_ecvsp_wl_interface,
+ pd,
+ _ecvsp_cb_wl_resource_destroy);
+
+ E_LIST_HANDLER_APPEND(pd->event_handlers, E_EVENT_CLIENT_REMOVE,
+ _ecvsp_cb_ec_remove, pd);
+
+ return pd;
+}
+
+static void
+_ecvsp_destroy(MY_HANDLE *pd)
+{
+ if (pd->wl.destroy_listener.notify)
+ {
+ wl_list_remove(&pd->wl.destroy_listener.link);
+ pd->wl.destroy_listener.notify = NULL;
+ }
+
+ E_FREE_LIST(pd->event_handlers, ecore_event_handler_del);
+
+ e_object_unref(E_OBJECT(pd->ec));
+}
+
+static void
+_ecvsp_commit_to_cache(MY_HANDLE *pd, E_Comp_Wl_Surface_State *src)
+{
+ E_Comp_Wl_Surface_State *dst;
+ struct wl_resource *cb;
+ Eina_List *l, *ll;
+ Eina_Iterator *itr;
+ Eina_Rectangle *rect;
+
+ DBG("Video Surface Provider Commit to Cache");
+
+ dst = &pd->sync.cache.data;
+
+ /* move pending damage */
+ EINA_LIST_FOREACH_SAFE(src->damages, l, ll, rect)
+ eina_list_move_list(&dst->damages, &src->damages, l);
+
+ EINA_LIST_FOREACH_SAFE(src->buffer_damages, l, ll, rect)
+ eina_list_move_list(&dst->buffer_damages, &src->buffer_damages, l);
+
+ if (src->new_attach)
+ {
+ dst->new_attach = EINA_TRUE;
+ e_comp_wl_surface_state_buffer_set(dst, src->buffer);
+ e_comp_wl_buffer_reference(&pd->sync.cache.buffer_ref, src->buffer);
+ }
+
+ dst->sx = src->sx;
+ dst->sy = src->sy;
+
+ dst->buffer_viewport.changed |= src->buffer_viewport.changed;
+ dst->buffer_viewport.buffer = src->buffer_viewport.buffer;
+ dst->buffer_viewport.surface = src->buffer_viewport.surface;
+
+ e_comp_wl_surface_state_buffer_set(src, NULL);
+ src->sx = 0;
+ src->sy = 0;
+ src->new_attach = EINA_FALSE;
+ src->buffer_viewport.changed = 0;
+
+ /* copy src->opaque into dst->opaque */
+ itr = eina_tiler_iterator_new(src->opaque);
+ EINA_ITERATOR_FOREACH(itr, rect)
+ eina_tiler_rect_add(dst->opaque, rect);
+ eina_iterator_free(itr);
+
+ /* repeat for input */
+ itr = eina_tiler_iterator_new(src->input);
+ EINA_ITERATOR_FOREACH(itr, rect)
+ eina_tiler_rect_add(dst->input, rect);
+ eina_iterator_free(itr);
+
+ EINA_LIST_FOREACH_SAFE(src->frames, l, ll, cb)
+ {
+ if (cb)
+ eina_list_move_list(&dst->frames, &src->frames, l);
+ }
+
+ dst->has_data = EINA_TRUE;
+}
+
+static void
+_ecvsp_commit_from_cache(MY_HANDLE *pd)
+{
+ e_comp_wl_surface_state_commit(pd->ec, &pd->sync.cache.data);
+ e_comp_wl_buffer_reference(&pd->sync.cache.buffer_ref, NULL);
+}
+
+static void
+_ecvsp_commit(MY_HANDLE *pd)
+{
+ E_Client *subc;
+ Eina_List *l;
+
+ if (pd->sync.cache.data.has_data)
+ {
+ _ecvsp_commit_to_cache(pd, &pd->ec->comp_data->pending);
+ _ecvsp_commit_from_cache(pd);
+ }
+ else
+ e_comp_wl_surface_commit(pd->ec);
+
+ EINA_LIST_FOREACH(pd->ec->comp_data->sub.list, l, subc)
+ {
+ if (pd->ec != subc)
+ e_comp_wl_subsurface_parent_commit(subc, EINA_FALSE);
+ }
+
+ EINA_LIST_FOREACH(pd->ec->comp_data->sub.below_list, l, subc)
+ {
+ if (pd->ec != subc)
+ e_comp_wl_subsurface_parent_commit(subc, EINA_FALSE);
+ }
+
+ /* notify sync done to wl_client */
+ tizen_video_surface_provider_send_sync_done(pd->wl.resource,
+ pd->sync.serial);
+
+ pd->sync.enabled = EINA_FALSE;
+}
+
+static Eina_Bool
+_ecvsp_cb_surface_tree_foreach(void *data, E_Client *ec)
+{
+ MY_HANDLE *pd;
+ Eina_Bool res;
+ uint32_t serial;
+
+ pd = data;
+ res = e_client_video_sync_serial_get(ec, &serial);
+ if (res)
+ {
+ pd->sync.video_count++;
+ if (pd->sync.serial != serial)
+ {
+ pd->sync.done = EINA_FALSE;
+ return EINA_FALSE;
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecvsp_sync_done_check(MY_HANDLE *pd)
+{
+ pd->sync.video_count = 0;
+ pd->sync.done = EINA_TRUE;
+ e_client_surface_tree_foreach(pd->ec, _ecvsp_cb_surface_tree_foreach, pd);
+
+ if (pd->sync.video_count == 0)
+ {
+ /* Exception handling: Let's consider it as sync done. */
+ VER("CRI: cannot find video client", pd->ec);
+ return EINA_TRUE;
+ }
+
+ if (pd->sync.done)
+ {
+ VIN("sync done successfully", pd->ec);
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
e_client_video_property_disallow(video->ec);
}
+static void
+_e_comp_wl_video_object_cb_set_sync_serial(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial)
+{
+ E_Video *video;
+
+ video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ ELOGF("VDSYNC", "tizne_video_object.sync (serial %d)", video->ec, serial);
+
+ e_client_video_sync_serial_set(video->ec, serial);
+}
+
static const struct tizen_video_object_interface _e_comp_wl_video_object_interface =
{
_e_comp_wl_video_object_cb_destroy,
_e_comp_wl_video_object_cb_unfollow_topmost_visibility,
_e_comp_wl_video_object_cb_allowed_attribute,
_e_comp_wl_video_object_cb_disallowed_attribute,
+ _e_comp_wl_video_object_cb_set_sync_serial,
};
static void
wl_resource_destroy(resource);
}
+static void
+_e_comp_wl_video_cb_get_surface_provider(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface)
+{
+ E_Client *ec;
+ struct wl_resource *new_resource;
+
+ ec = wl_resource_get_user_data(surface);
+ if (!ec)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid object");
+ return;
+ }
+
+ ELOGF("VDSYNC", "get_surface_provider", ec);
+
+ new_resource = wl_resource_create(client,
+ &tizen_video_surface_provider_interface,
+ wl_resource_get_version(resource),
+ id);
+
+ e_client_video_surface_provider_set(ec, new_resource);
+}
+
static const struct tizen_video_interface _e_comp_wl_video_interface =
{
_e_comp_wl_video_cb_get_object,
_e_comp_wl_video_cb_get_viewport,
_e_comp_wl_video_cb_destroy,
+ _e_comp_wl_video_cb_get_surface_provider,
};
static void
/* try to add tizen_video to wayland globals */
e_comp->wl_comp_data->video.global =
- wl_global_create(e_comp_wl->wl.disp, &tizen_video_interface, 1, NULL, _e_comp_wl_video_cb_bind);
+ wl_global_create(e_comp_wl->wl.disp, &tizen_video_interface, 2, NULL, _e_comp_wl_video_cb_bind);
if (!e_comp->wl_comp_data->video.global)
{