ENLIGHTENMENTHEADERS += \
src/bin/e_comp_wl_rsm.h \
-src/bin/e_comp_wl_video.h \
-src/bin/e_comp_wl_video_buffer.h \
+src/bin/video/e_comp_wl_video.h \
+src/bin/video/e_comp_wl_video_buffer.h \
+src/bin/video/e_client_video.h \
+src/bin/video/e_zone_video.h \
+src/bin/video/e_video_debug.h \
src/bin/e_comp_wl_viewport.h \
src/bin/e_comp_wl_screenshooter.h \
src/bin/e_comp_wl_shell.h \
enlightenment_src += \
src/bin/e_comp_wl_rsm.c \
-src/bin/e_comp_wl_video.c \
-src/bin/e_comp_wl_video_buffer.c \
+src/bin/video/e_comp_wl_video.c \
+src/bin/video/e_comp_wl_video_buffer.c \
+src/bin/video/e_client_video.c \
+src/bin/video/e_zone_video.c \
+src/bin/video/e_video_debug.c \
+src/bin/video/iface/e_video_hwc_planes.c \
+src/bin/video/iface/e_video_fallback.c \
src/bin/e_comp_wl_viewport.c \
src/bin/e_comp_wl_screenshooter.c \
src/bin/e_comp_wl_shell.c \
}
INF("HWC: =========================================================================");
}
+
+#define NUM_SW_FORMAT (sizeof(sw_formats) / sizeof(sw_formats[0]))
+
+static tbm_format sw_formats[] = {
+ TBM_FORMAT_ARGB8888,
+ TBM_FORMAT_XRGB8888,
+ TBM_FORMAT_YUV420,
+ TBM_FORMAT_YVU420,
+};
+
+static tdm_layer *
+_e_comp_screen_video_tdm_layer_get(tdm_output *output)
+{
+ int i, count = 0;
+#ifdef CHECKING_PRIMARY_ZPOS
+ int primary_idx = 0, primary_zpos = 0;
+ tdm_layer *primary_layer;
+#endif
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+ tdm_output_get_layer_count(output, &count);
+ for (i = 0; i < count; i++)
+ {
+ tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+ tdm_layer_capability capabilities = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+ if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
+ return layer;
+ }
+
+#ifdef CHECKING_PRIMARY_ZPOS
+ tdm_output_get_primary_index(output, &primary_idx);
+ primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
+ tdm_layer_get_zpos(primary_layer, &primary_zpos);
+#endif
+
+ for (i = 0; i < count; i++)
+ {
+ tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+ tdm_layer_capability capabilities = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+ if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
+ {
+#ifdef CHECKING_PRIMARY_ZPOS
+ int zpos = 0;
+ tdm_layer_get_zpos(layer, &zpos);
+ if (zpos >= primary_zpos) continue;
+#endif
+ return layer;
+ }
+ }
+
+ return NULL;
+}
+
+static E_Output *
+_e_comp_screen_eoutput_get_by_toutput(tdm_output *output)
+{
+ Eina_List *l;
+ E_Output *eo;
+
+ EINA_LIST_FOREACH(e_comp->e_comp_screen->outputs, l, eo)
+ if (eo->toutput == output)
+ return eo;
+
+ return NULL;
+}
+
+EINTERN Eina_Bool
+e_comp_screen_available_video_formats_get(const tbm_format **formats, int *count)
+{
+ E_Output *output;
+ tdm_output *toutput;
+ tdm_layer *layer;
+ tdm_error error;
+
+ *count = 0;
+
+ if (e_comp_screen_pp_support())
+ {
+ error = tdm_display_get_pp_available_formats(e_comp->e_comp_screen->tdisplay, formats, count);
+ if (error == TDM_ERROR_NONE)
+ return EINA_TRUE;
+ }
+
+ /* get the first output */
+ toutput = tdm_display_get_output(e_comp->e_comp_screen->tdisplay, 0, NULL);
+ if (!toutput)
+ return EINA_FALSE;
+
+ output = _e_comp_screen_eoutput_get_by_toutput(toutput);
+ if (!output)
+ return EINA_FALSE;
+
+ if (e_hwc_policy_get(output->hwc) != E_HWC_POLICY_WINDOWS)
+ {
+ /* get the first suitable layer */
+ layer = _e_comp_screen_video_tdm_layer_get(toutput);
+ if (layer)
+ {
+ tdm_layer_get_available_formats(layer, formats, count);
+ }
+ else
+ {
+ *formats = sw_formats;
+ *count = NUM_SW_FORMAT;
+ }
+ }
+ else
+ {
+ error = tdm_hwc_get_video_supported_formats(output->hwc->thwc, formats, count);
+ if (error != TDM_ERROR_NONE)
+ {
+ *formats = sw_formats;
+ *count = NUM_SW_FORMAT;
+ }
+ }
+
+ return EINA_TRUE;
+}
EINTERN Eina_Bool e_comp_screen_pp_support(void);
EINTERN Eina_List * e_comp_screen_pp_available_formats_get(void);
+EINTERN Eina_Bool e_comp_screen_available_video_formats_get(const tbm_format **formats, int *count);
+
#endif /*E_COMP_SCREEN_H*/
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "e.h"
-#include <tdm.h>
-#include <values.h>
-#include <tdm_helper.h>
-#include <wayland-tbm-server.h>
-#include <tizen-extension-server-protocol.h>
-
-//#define DUMP_BUFFER
-#define CHECKING_PRIMARY_ZPOS
-
-static int _video_detail_log_dom = -1;
-static Eina_Bool video_to_primary;
-static Eina_Bool video_punch;
-
-#define BUFFER_MAX_COUNT 5
-#define MIN_WIDTH 32
-
-#undef NEVER_GET_HERE
-#define NEVER_GET_HERE() CRI("** need to improve more **")
-
-#ifndef CLEAR
-#define CLEAR(x) memset(&(x), 0, sizeof(x))
-#endif
-
-#define VER(fmt, arg...) ELOGF("VIDEO", "<ERR> window(0x%08"PRIxPTR"): "fmt, \
- video->ec->pixmap, video->ec, video->window, ##arg)
-#define VWR(fmt, arg...) ELOGF("VIDEO", "<WRN> window(0x%08"PRIxPTR"): "fmt, \
- video->ec->pixmap, video->ec, video->window, ##arg)
-#define VIN(fmt, arg...) ELOGF("VIDEO", "<INF> window(0x%08"PRIxPTR"): "fmt, \
- video->ec->pixmap, video->ec, video->window, ##arg)
-#define VDB(fmt, arg...) DBG("window(0x%08"PRIxPTR") ec(%p): "fmt, video->window, video->ec, ##arg)
-
-#define DET(...) EINA_LOG_DOM_DBG(_video_detail_log_dom, __VA_ARGS__)
-#define VDT(fmt, arg...) DET("window(0x%08"PRIxPTR"): "fmt, video->window, ##arg)
-
-#define GEO_FMT "%dx%d(%dx%d+%d+%d) -> (%dx%d+%d+%d) transform(%d)"
-#define GEO_ARG(g) \
- (g)->input_w, (g)->input_h, \
- (g)->input_r.w, (g)->input_r.h, (g)->input_r.x, (g)->input_r.y, \
- (g)->output_r.w, (g)->output_r.h, (g)->output_r.x, (g)->output_r.y, \
- (g)->transform
-
-struct _E_Video_Info_Layer
-{
- tdm_info_config src_config;
- tdm_pos dst_pos;
- tdm_transform transform;
-};
-
-/* the new TDM API doesn't have layers, so we have to invent layer here*/
-struct _E_Video_Layer
-{
- E_Video *video;
-
- tdm_layer *tdm_layer;
-
- /* for hwc_window */
- E_Video_Info_Layer info;
- tbm_surface_h cur_tsurface; // tsurface to be set this layer.
- E_Client *e_client;
-};
-
-struct _E_Video
-{
- struct wl_resource *video_object;
- struct wl_resource *surface;
- E_Client *ec;
- Ecore_Window window;
- tdm_output *output;
- E_Output *e_output;
- E_Video_Layer *layer;
- E_Plane *e_plane;
- Eina_Bool external_video;
-
- /* input info */
- tbm_format tbmfmt;
- Eina_List *input_buffer_list;
-
- /* in screen coordinates */
- struct
- {
- int input_w, input_h; /* input buffer's size */
- Eina_Rectangle input_r; /* input buffer's content rect */
- Eina_Rectangle output_r; /* video plane rect */
- uint transform; /* rotate, flip */
-
- Eina_Rectangle tdm_output_r; /* video plane rect in physical output coordinates */
- uint tdm_transform; /* rotate, flip in physical output coordinates */
- } geo, old_geo;
-
- E_Comp_Wl_Buffer *old_comp_buffer;
-
- /* converter info */
- tbm_format pp_tbmfmt;
- tdm_pp *pp;
- Eina_Rectangle pp_r; /* converter dst content rect */
- Eina_List *pp_buffer_list;
- Eina_List *next_buffer;
- Eina_Bool pp_scanout;
-
- int output_align;
- int pp_align;
- int pp_minw, pp_minh, pp_maxw, pp_maxh;
- int video_align;
-
- /* When a video buffer be attached, it will be appended to the end of waiting_list .
- * And when it's committed, it will be moved to committed_list.
- * Finally when the commit handler is called, it will become current_fb.
- */
- Eina_List *waiting_list; /* buffers which are not committed yet */
- Eina_List *committed_list; /* buffers which are committed, but not shown on screen yet */
- E_Comp_Wl_Video_Buf *current_fb; /* buffer which is showing on screen currently */
- Eina_Bool waiting_vblank;
-
- /* attributes */
- Eina_List *tdm_prop_list;
- Eina_List *late_tdm_prop_list;
- int tdm_mute_id;
-
- Eina_Bool cb_registered;
- Eina_Bool need_force_render;
- Eina_Bool follow_topmost_visibility;
- Eina_Bool allowed_attribute;
-
- E_Plane_Hook *video_plane_ready_handler;
-};
-
-typedef struct _Tdm_Prop_Value
-{
- unsigned int id;
- char name[TDM_NAME_LEN];
- tdm_value value;
-} Tdm_Prop_Value;
-
-static tbm_format sw_formats[] = {
- TBM_FORMAT_ARGB8888,
- TBM_FORMAT_XRGB8888,
- TBM_FORMAT_YUV420,
- TBM_FORMAT_YVU420,
-};
-
-#define NUM_SW_FORMAT (sizeof(sw_formats) / sizeof(sw_formats[0]))
-
-static Eina_List *video_list = NULL;
-static Eina_List *video_layers = NULL;
-
-static void _e_video_set(E_Video *video, E_Client *ec);
-static void _e_video_destroy(E_Video *video);
-static void _e_video_render(E_Video *video, const char *func);
-static Eina_Bool _e_video_frame_buffer_show(E_Video *video, E_Comp_Wl_Video_Buf *vbuf);
-static void _e_video_video_set_hook(void *data, E_Plane *plane);
-
-static tdm_layer* _e_video_tdm_video_layer_get(tdm_output *output);
-static tdm_layer* _e_video_tdm_available_video_layer_get(tdm_output *output);
-static void _e_video_tdm_set_layer_usable(tdm_layer *layer, Eina_Bool usable);
-static Eina_Bool _e_video_tdm_get_layer_usable(tdm_layer *layer);
-
-static void _e_video_vblank_handler(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data);
-
-static int
-gcd(int a, int b)
-{
- if (a % b == 0)
- return b;
- return gcd(b, a % b);
-}
-
-static int
-lcm(int a, int b)
-{
- return a * b / gcd(a, b);
-}
-
-static void
-buffer_transform(int width, int height, uint32_t transform, int32_t scale,
- int sx, int sy, int *dx, int *dy)
-{
- switch (transform)
- {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- default:
- *dx = sx, *dy = sy;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- *dx = width - sx, *dy = sy;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- *dx = height - sy, *dy = sx;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- *dx = height - sy, *dy = width - sx;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- *dx = width - sx, *dy = height - sy;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- *dx = sx, *dy = height - sy;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- *dx = sy, *dy = width - sx;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- *dx = sy, *dy = sx;
- break;
- }
-
- *dx *= scale;
- *dy *= scale;
-}
-
-static E_Video *
-find_video_with_surface(struct wl_resource *surface)
-{
- E_Video *video;
- Eina_List *l;
- EINA_LIST_FOREACH(video_list, l, video)
- {
- if (video->surface == surface)
- return video;
- }
- return NULL;
-}
-
-static E_Client *
-find_video_child_get(E_Client *ec)
-{
- E_Client *subc = NULL;
- Eina_List *l;
- if (!ec) return NULL;
- if (e_object_is_del(E_OBJECT(ec))) return NULL;
- if (!ec->comp_data) return NULL;
-
- if (ec->comp_data->video_client) return ec;
-
- EINA_LIST_FOREACH(ec->comp_data->sub.below_list, l, subc)
- {
- E_Client *temp= NULL;
- if (!subc->comp_data || e_object_is_del(E_OBJECT(subc))) continue;
- temp = find_video_child_get(subc);
- if(temp) return temp;
- }
-
- return NULL;
-}
-
-static E_Client *
-find_offscreen_parent_get(E_Client *ec)
-{
- E_Client *parent = NULL;
-
- if (!ec->comp_data || !ec->comp_data->sub.data)
- return NULL;
-
- parent = ec->comp_data->sub.data->parent;
- while (parent)
- {
- if (!parent->comp_data || !parent->comp_data->sub.data)
- return NULL;
-
- if (parent->comp_data->sub.data->remote_surface.offscreen_parent)
- return parent->comp_data->sub.data->remote_surface.offscreen_parent;
-
- parent = parent->comp_data->sub.data->parent;
- }
-
- return NULL;
-}
-
-static E_Comp_Wl_Video_Buf *
-_e_video_vbuf_find(Eina_List *list, tbm_surface_h buffer)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l = NULL;
-
- EINA_LIST_FOREACH(list, l, vbuf)
- {
- if (vbuf->tbm_surface == buffer)
- return vbuf;
- }
-
- return NULL;
-}
-
-static E_Comp_Wl_Video_Buf *
-_e_video_vbuf_find_with_comp_buffer(Eina_List *list, E_Comp_Wl_Buffer *comp_buffer)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l = NULL;
-
- EINA_LIST_FOREACH(list, l, vbuf)
- {
- if (vbuf->comp_buffer == comp_buffer)
- return vbuf;
- }
-
- return NULL;
-}
-
-static E_Output *
-_get_e_output(tdm_output *output)
-{
- Eina_List *l;
- E_Output *eo;
-
- EINA_LIST_FOREACH(e_comp->e_comp_screen->outputs, l, eo)
- if (eo->toutput == output)
- return eo;
-
- return NULL;
-}
-
-static Eina_Bool
-_e_video_tdm_output_has_video_layer(tdm_output *toutput)
-{
- E_Output *output = NULL;
- tdm_layer *layer;
- tdm_layer_capability lyr_capabilities = 0;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(toutput, EINA_FALSE);
-
- output = _get_e_output(toutput);
- EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
-
- if (e_hwc_policy_get(output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- /* get the first suitable layer */
- layer = _e_video_tdm_video_layer_get(toutput);
- if (!layer)
- return EINA_FALSE;
-
- tdm_layer_get_capabilities(layer, &lyr_capabilities);
- if (lyr_capabilities & TDM_LAYER_CAPABILITY_VIDEO)
- return EINA_TRUE;
- }
- else
- {
- /* TODO: add the hwc_window video support */
- ;;;;
- }
-
- return EINA_FALSE;
-}
-
-E_Video_Layer *
-_e_video_available_video_layer_get(E_Video *video)
-{
- E_Video_Layer *layer = NULL;
- E_Hwc_Window *hwc_window = NULL;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(video, NULL);
-
- layer = calloc(1, sizeof(E_Video_Layer));
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
-
- layer->video = video;
- layer->e_client = video->ec;
-
- if (e_hwc_policy_get(video->e_output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- layer->tdm_layer = _e_video_tdm_available_video_layer_get(video->output);
- if (!layer->tdm_layer)
- {
- free(layer);
- return NULL;
- }
- _e_video_tdm_set_layer_usable(layer->tdm_layer, EINA_FALSE);
- }
- else
- {
- /*
- * Try to create a video hwc window.
- * In this moment the video resource will be held.
- */
- hwc_window = e_hwc_window_new(video->e_output->hwc, video->ec, E_HWC_WINDOW_STATE_VIDEO);
- if (!hwc_window)
- {
- VER("hwc_opt: cannot create new video hwc window for ec(%p)", video->ec);
- free(layer);
- return NULL;
- }
-
- /* free previous hwc_window */
- if (video->ec->hwc_window)
- e_hwc_window_free(video->ec->hwc_window);
-
- /* set new hwc_window to the e_client */
- video->ec->hwc_window = hwc_window;
- }
-
- return layer;
-}
-
-/* this function is called on the start work with client while the video interface is bind */
-static void
-_e_video_get_available_formats(const tbm_format **formats, int *count)
-{
- E_Output *output;
- tdm_output *toutput;
- tdm_layer *layer;
-
- *count = 0;
-
- /* get the first output */
- toutput = tdm_display_get_output(e_comp->e_comp_screen->tdisplay, 0, NULL);
- EINA_SAFETY_ON_NULL_RETURN(toutput);
-
- output = _get_e_output(toutput);
- EINA_SAFETY_ON_NULL_RETURN(output);
-
- if (e_hwc_policy_get(output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- /* get the first suitable layer */
- layer = _e_video_tdm_video_layer_get(toutput);
- if (layer)
- {
- tdm_layer_get_available_formats(layer, formats, count);
- }
- else
- {
- *formats = sw_formats;
- *count = NUM_SW_FORMAT;
- }
- }
- else
- {
- tdm_error error;
- error = tdm_hwc_get_video_supported_formats(output->hwc->thwc, formats, count);
- if (error != TDM_ERROR_NONE)
- {
- *formats = sw_formats;
- *count = NUM_SW_FORMAT;
- }
- }
-}
-
-static int
-_e_video_get_prop_id(E_Video *video, const char *name)
-{
- tdm_layer *layer;
- const tdm_prop *props;
- int i, count = 0;
-
- if (e_hwc_policy_get(video->e_output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- layer = _e_video_tdm_video_layer_get(video->output);
- tdm_layer_get_available_properties(layer, &props, &count);
-
- for (i = 0; i < count; i++)
- {
- if (!strncmp(name, props[i].name, TDM_NAME_LEN))
- {
- VDB("check property(%s)", name);
- return props[i].id;
- }
- }
- }
- else
- {
- // TODO: hwc windows don't have any properties yet
- // video hwc_window has to get and set the property id.
- // tdm_error tdm_hwc_window_video_get_property(tdm_hwc_window *hwc_window, uint32_t id, tdm_value *value);
- ;;;;;
- }
-
- return -1;
-}
-
-// TODO: this function has to be removed.....
-// Use. e_hwc_policy_get();
-static Eina_Bool
-_is_video_hwc_windows(E_Video *video)
-{
- EINA_SAFETY_ON_NULL_RETURN_VAL(video, EINA_FALSE);
- EINA_SAFETY_ON_NULL_RETURN_VAL(video->e_output, EINA_FALSE);
-
- if (e_hwc_policy_get(video->e_output->hwc) == E_HWC_POLICY_WINDOWS)
- return EINA_TRUE;
-
- return EINA_FALSE;
-}
-
-static tdm_error
-_e_video_layer_get_info(E_Video_Layer *layer, E_Video_Info_Layer *vinfo)
-{
- tdm_error ret = TDM_ERROR_NONE;
- tdm_info_layer tinfo = {0};
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_INVALID_PARAMETER);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, TDM_ERROR_INVALID_PARAMETER);
-
- if (_is_video_hwc_windows(layer->video))
- memcpy(vinfo, &layer->info, sizeof(E_Video_Info_Layer));
- else
- {
- ret = tdm_layer_get_info(layer->tdm_layer, &tinfo);
- EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
-
- memcpy(&vinfo->src_config, &tinfo.src_config, sizeof(tdm_info_config));
- memcpy(&vinfo->dst_pos, &tinfo.dst_pos, sizeof(tdm_pos));
- vinfo->transform = tinfo.transform;
- }
-
- return ret;
-}
-
-static tdm_error
-_e_video_layer_set_info(E_Video_Layer *layer, E_Video_Info_Layer *vinfo)
-{
- tdm_error ret = TDM_ERROR_NONE;
- tdm_info_layer info_layer = {0};
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_INVALID_PARAMETER);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, TDM_ERROR_INVALID_PARAMETER);
-
- if (_is_video_hwc_windows(layer->video))
- memcpy(&layer->info, vinfo, sizeof(E_Video_Info_Layer));
- else
- {
-
- memcpy(&info_layer.src_config, &vinfo->src_config, sizeof(tdm_info_config));
- memcpy(&info_layer.dst_pos, &vinfo->dst_pos, sizeof(tdm_pos));
- info_layer.transform = vinfo->transform;
-
- ret = tdm_layer_set_info(layer->tdm_layer, &info_layer);
- }
-
- return ret;
-}
-
-static tdm_error
-_e_video_layer_set_buffer(E_Video_Layer * layer, tbm_surface_h buff)
-{
- tdm_error ret = TDM_ERROR_NONE;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
- EINA_SAFETY_ON_NULL_RETURN_VAL(buff, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- layer->cur_tsurface = buff; // set the buffer to the tdm at the e_hwc_window_buffer_update();
- else
- ret = tdm_layer_set_buffer(layer->tdm_layer, buff);
-
- return ret;
-}
-
-static tdm_error
-_e_video_layer_unset_buffer(E_Video_Layer *layer)
-{
- tdm_error ret;
- E_Hwc_Window *hwc_window;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- {
- hwc_window = layer->e_client->hwc_window;
- EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, TDM_ERROR_OPERATION_FAILED);
-
- e_hwc_window_state_set(hwc_window, E_HWC_WINDOW_STATE_NONE, EINA_TRUE);
- layer->cur_tsurface = NULL; // set the buffer to the tdm at the e_hwc_window_buffer_update();
-
- ret = TDM_ERROR_NONE;
- }
- else
- ret = tdm_layer_unset_buffer(layer->tdm_layer);
-
- return ret;
-}
-
-/*
- * This function checks if this layer was set
- */
-static tdm_error
-_e_video_layer_is_usable(E_Video_Layer * layer, unsigned int *usable)
-{
- tdm_error ret;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
- EINA_SAFETY_ON_NULL_RETURN_VAL(usable, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- {
- E_Hwc_Window *hwc_window;
- E_Hwc_Window_State state;
-
- hwc_window = layer->e_client->hwc_window;
- EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, TDM_ERROR_OPERATION_FAILED);
-
- state = e_hwc_window_state_get(hwc_window);
- if (state == E_HWC_WINDOW_STATE_NONE || state == E_HWC_WINDOW_STATE_CLIENT)
- *usable = 1;
- else
- *usable = 0;
-
- return TDM_ERROR_NONE;
- }
-
- ret = tdm_layer_is_usable(layer->tdm_layer, usable);
- return ret;
-}
-
-static tdm_error
-_e_video_layer_commit(E_Video_Layer *layer, tdm_layer_commit_handler func, void *user_data)
-{
- tdm_error ret = TDM_ERROR_NONE;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- ret = TDM_ERROR_NONE;
- else
- ret = tdm_layer_commit(layer->tdm_layer, func, user_data);
-
- return ret;
-}
-
-static tbm_surface_h
-_e_video_layer_get_displaying_buffer(E_Video_Layer *layer, int *tdm_error)
-{
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
-
- if (tdm_error)
- *tdm_error = TDM_ERROR_OPERATION_FAILED;
-
- if (_is_video_hwc_windows(layer->video))
- {
- E_Hwc_Window *hwc_window;
-
- hwc_window = layer->e_client->hwc_window;
- EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, NULL);
-
- if (tdm_error)
- *tdm_error = TDM_ERROR_NONE;
-
- return e_hwc_window_displaying_surface_get(hwc_window);
- }
-
- return tdm_layer_get_displaying_buffer(layer->tdm_layer, tdm_error);
-}
-
-static tdm_error
-_e_video_layer_get_available_properties(E_Video_Layer * layer, const tdm_prop **props,
- int *count)
-{
- tdm_error ret = TDM_ERROR_OPERATION_FAILED;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
- EINA_SAFETY_ON_NULL_RETURN_VAL(props, TDM_ERROR_BAD_REQUEST);
- EINA_SAFETY_ON_NULL_RETURN_VAL(count, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- {
- *count = 0;
-#if 0 //TODO:
- if (layer->e_client->hwc_window->thwc_window)
- ret = tdm_hwc_window_video_get_available_properties(
- layer->e_client->hwc_window->thwc_window, props, count);
-#endif
- }
- else
- {
- tdm_layer *tlayer = layer->tdm_layer;
- /* if layer wasn't set then get an any available tdm_layer */
- if (tlayer == NULL)
- tlayer = _e_video_tdm_available_video_layer_get(layer->video->output);
- ret = tdm_layer_get_available_properties(tlayer, props, count);
- }
-
- return ret;
-}
-
-static tdm_error
-_e_video_layer_get_property(E_Video_Layer * layer, unsigned id, tdm_value *value)
-{
- tdm_error ret = TDM_ERROR_OPERATION_FAILED;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
- EINA_SAFETY_ON_NULL_RETURN_VAL(value, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- {
-#if 0 //TODO:
- if (layer->e_client->hwc_window->thwc_window)
- ret = tdm_hwc_window_video_get_property(
- layer->e_client->hwc_window->thwc_window, id, value);
- else
-#endif
- ret = TDM_ERROR_BAD_MODULE;
- }
- else
- ret = tdm_layer_get_property(layer->tdm_layer, id, value);
-
- return ret;
-}
-
-static tdm_error
-_e_video_layer_set_property(E_Video_Layer * layer, Tdm_Prop_Value *prop)
-{
- tdm_error ret;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
-
- if (_is_video_hwc_windows(layer->video))
- return TDM_ERROR_BAD_MODULE;
-
- ret = tdm_layer_set_property(layer->tdm_layer, prop->id, prop->value);
- return ret;
-}
-
-static void
-_e_video_layer_destroy(E_Video_Layer *layer)
-{
- EINA_SAFETY_ON_NULL_RETURN(layer);
-
- if (layer->e_client && layer->e_client->hwc_window)
- {
- E_Hwc_Window *hwc_window;
-
- hwc_window = layer->e_client->hwc_window;
- EINA_SAFETY_ON_FALSE_RETURN(hwc_window);
-
- e_hwc_window_free(hwc_window);
- layer->e_client->hwc_window = NULL;
-
- /* to re-evaluate the window policy */
- e_comp_render_queue();
- }
-
- if (layer->tdm_layer)
- _e_video_tdm_set_layer_usable(layer->tdm_layer, EINA_TRUE);
-
- free(layer);
-}
-
-static Eina_Bool
-_e_video_set_layer(E_Video *video, Eina_Bool set)
-{
- Eina_Bool need_wait;
-
- if (!set)
- {
- unsigned int usable = 1;
- if (!video->layer) return EINA_TRUE;
-
- _e_video_layer_is_usable(video->layer, &usable);
- if (!usable && !video->video_plane_ready_handler)
- {
- VIN("stop video");
- _e_video_layer_unset_buffer(video->layer);
- _e_video_layer_commit(video->layer, NULL, NULL);
- }
-
- VIN("release layer: %p", video->layer);
- _e_video_layer_destroy(video->layer);
- video->layer = NULL;
- video->old_comp_buffer = NULL;
-
- if (e_hwc_policy_get(video->e_output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- e_plane_video_set(video->e_plane, EINA_FALSE, NULL);
- video->e_plane = NULL;
- }
-
- E_FREE_FUNC(video->video_plane_ready_handler, e_plane_hook_del);
- }
- else
- {
- int zpos;
- tdm_error ret;
-
- if (video->layer) return EINA_TRUE;
-
- video->layer = _e_video_available_video_layer_get(video);
- if (!video->layer)
- {
- VWR("no available layer for video");
- return EINA_FALSE;
- }
-
- if (e_hwc_policy_get(video->e_output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- ret = tdm_layer_get_zpos(video->layer->tdm_layer, &zpos);
- if (ret == TDM_ERROR_NONE)
- video->e_plane = e_output_plane_get_by_zpos(video->e_output, zpos);
-
- if (!video->e_plane)
- {
- VWR("fail get e_plane");
- _e_video_layer_destroy(video->layer);
- video->layer = NULL;
- return EINA_FALSE;
- }
-
- if (!e_plane_video_set(video->e_plane, EINA_TRUE, &need_wait))
- {
- VWR("fail set video to e_plane");
- _e_video_layer_destroy(video->layer);
- video->layer = NULL;
- video->e_plane = NULL;
- return EINA_FALSE;
- }
- if (need_wait)
- {
- video->video_plane_ready_handler =
- e_plane_hook_add(E_PLANE_HOOK_VIDEO_SET,
- _e_video_video_set_hook, video);
- }
- }
-
- VIN("assign layer: %p", video->layer);
- }
-
- return EINA_TRUE;
-}
-
-static Eina_Bool
-_e_video_is_visible(E_Video *video)
-{
- E_Client *offscreen_parent;
-
- if (e_object_is_del(E_OBJECT(video->ec))) return EINA_FALSE;
-
- if (!e_pixmap_resource_get(video->ec->pixmap))
- {
- VDB("no comp buffer");
- return EINA_FALSE;
- }
-
- if (video->ec->comp_data->sub.data && video->ec->comp_data->sub.data->stand_alone)
- return EINA_TRUE;
-
- offscreen_parent = find_offscreen_parent_get(video->ec);
- if (offscreen_parent && offscreen_parent->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED)
- {
- VDB("video surface invisible: offscreen fully obscured");
- return EINA_FALSE;
- }
-
- if (!evas_object_visible_get(video->ec->frame))
- {
- VDB("evas obj invisible");
- return EINA_FALSE;
- }
-
- return EINA_TRUE;
-}
-
-static Eina_Bool
-_e_video_parent_is_viewable(E_Video *video)
-{
- E_Client *topmost_parent;
-
- if (e_object_is_del(E_OBJECT(video->ec))) return EINA_FALSE;
-
- topmost_parent = e_comp_wl_topmost_parent_get(video->ec);
-
- if (!topmost_parent)
- return EINA_FALSE;
-
- if (topmost_parent == video->ec)
- {
- VDB("There is no video parent surface");
- return EINA_FALSE;
- }
-
- if (!topmost_parent->visible)
- {
- VDB("parent(0x%08"PRIxPTR") not viewable", (Ecore_Window)e_client_util_win_get(topmost_parent));
- return EINA_FALSE;
- }
-
- if (!e_pixmap_resource_get(topmost_parent->pixmap))
- {
- VDB("parent(0x%08"PRIxPTR") no comp buffer", (Ecore_Window)e_client_util_win_get(topmost_parent));
- return EINA_FALSE;
- }
-
- return EINA_TRUE;
-}
-
-static void
-_e_video_input_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
-{
- E_Video *video = data;
- Eina_Bool need_hide = EINA_FALSE;
-
- VDT("Buffer(%p) to be free, refcnt(%d)", vbuf, vbuf->ref_cnt);
-
- video->input_buffer_list = eina_list_remove(video->input_buffer_list, vbuf);
-
- if (vbuf->comp_buffer)
- e_comp_wl_buffer_reference(&vbuf->buffer_ref, NULL);
-
- if (video->current_fb == vbuf)
- {
- VIN("current fb destroyed");
- e_comp_wl_video_buffer_set_use(video->current_fb, EINA_FALSE);
- video->current_fb = NULL;
- need_hide = EINA_TRUE;
- }
-
- if (eina_list_data_find(video->committed_list, vbuf))
- {
- VIN("committed fb destroyed");
- video->committed_list = eina_list_remove(video->committed_list, vbuf);
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
- need_hide = EINA_TRUE;
- }
-
- if (eina_list_data_find(video->waiting_list, vbuf))
- {
- VIN("waiting fb destroyed");
- video->waiting_list = eina_list_remove(video->waiting_list, vbuf);
- }
-
- if (need_hide && video->layer)
- _e_video_frame_buffer_show(video, NULL);
-}
-
-static Eina_Bool
-_e_video_input_buffer_scanout_check(E_Comp_Wl_Video_Buf *vbuf)
-{
- tbm_surface_h tbm_surface = NULL;
- tbm_bo bo = NULL;
- int flag;
-
- tbm_surface = vbuf->tbm_surface;
- EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, EINA_FALSE);
-
- bo = tbm_surface_internal_get_bo(tbm_surface, 0);
- EINA_SAFETY_ON_NULL_RETURN_VAL(bo, EINA_FALSE);
-
- flag = tbm_bo_get_flags(bo);
- if (flag == TBM_BO_SCANOUT)
- return EINA_TRUE;
-
- return EINA_FALSE;
-}
-
-static E_Comp_Wl_Video_Buf *
-_e_video_input_buffer_copy(E_Video *video, E_Comp_Wl_Buffer *comp_buf, E_Comp_Wl_Video_Buf *vbuf, Eina_Bool scanout)
-{
- E_Comp_Wl_Video_Buf *temp = NULL;
- int aligned_width = ROUNDUP(vbuf->width_from_pitch, video->pp_align);
-
- temp = e_comp_wl_video_buffer_alloc(aligned_width, vbuf->height, vbuf->tbmfmt, scanout);
- EINA_SAFETY_ON_NULL_RETURN_VAL(temp, NULL);
-
- temp->comp_buffer = comp_buf;
-
- VDB("copy vbuf(%d,%dx%d) => vbuf(%d,%dx%d)",
- MSTAMP(vbuf), vbuf->width_from_pitch, vbuf->height,
- MSTAMP(temp), temp->width_from_pitch, temp->height);
-
- e_comp_wl_video_buffer_copy(vbuf, temp);
- e_comp_wl_video_buffer_unref(vbuf);
-
- video->geo.input_w = vbuf->width_from_pitch;
-#ifdef DUMP_BUFFER
- char file[256];
- static int i;
- snprintf(file, sizeof file, "/tmp/dump/%s_%d.png", "cpy", i++);
- tdm_helper_dump_buffer(temp->tbm_surface, file);
-#endif
-
- return temp;
-}
-
-static E_Comp_Wl_Video_Buf *
-_e_video_input_buffer_get(E_Video *video, E_Comp_Wl_Buffer *comp_buffer, Eina_Bool scanout)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_Bool need_pp_scanout = EINA_FALSE;
-
- vbuf = _e_video_vbuf_find_with_comp_buffer(video->input_buffer_list, comp_buffer);
- if (vbuf)
- {
- vbuf->content_r = video->geo.input_r;
- return vbuf;
- }
-
- vbuf = e_comp_wl_video_buffer_create_comp(comp_buffer);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
-
- if (video->pp_scanout)
- {
- Eina_Bool input_buffer_scanout = EINA_FALSE;
- input_buffer_scanout = _e_video_input_buffer_scanout_check(vbuf);
- if (!input_buffer_scanout) need_pp_scanout = EINA_TRUE;
- }
-
- if (video->pp)
- {
- if ((video->pp_align != -1 && (vbuf->width_from_pitch % video->pp_align)) ||
- need_pp_scanout)
- {
- E_Comp_Wl_Video_Buf *temp;
-
- if (need_pp_scanout)
- temp = _e_video_input_buffer_copy(video, comp_buffer, vbuf, EINA_TRUE);
- else
- temp = _e_video_input_buffer_copy(video, comp_buffer, vbuf, scanout);
- if (!temp)
- {
- e_comp_wl_video_buffer_unref(vbuf);
- return NULL;
- }
- vbuf = temp;
- }
- }
-
- vbuf->content_r = video->geo.input_r;
-
- video->input_buffer_list = eina_list_append(video->input_buffer_list, vbuf);
- e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_input_buffer_cb_free, video);
-
- VDT("Client(%s):PID(%d) RscID(%d), Buffer(%p) created, refcnt:%d"
- " scanout=%d", e_client_util_name_get(video->ec) ?: "No Name" ,
- video->ec->netwm.pid, wl_resource_get_id(video->surface), vbuf,
- vbuf->ref_cnt, scanout);
-
- return vbuf;
-}
-
-static void
-_e_video_input_buffer_valid(E_Video *video, E_Comp_Wl_Buffer *comp_buffer)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l;
-
- EINA_LIST_FOREACH(video->input_buffer_list, l, vbuf)
- {
- tbm_surface_h tbm_surf;
- tbm_bo bo;
- uint32_t size = 0, offset = 0, pitch = 0;
-
- if (!vbuf->comp_buffer) continue;
- if (vbuf->resource == comp_buffer->resource)
- {
- WRN("got wl_buffer@%d twice", wl_resource_get_id(comp_buffer->resource));
- return;
- }
-
- tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
- bo = tbm_surface_internal_get_bo(tbm_surf, 0);
- tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
-
- if (vbuf->names[0] == tbm_bo_export(bo) && vbuf->offsets[0] == offset)
- {
- WRN("can tearing: wl_buffer@%d, wl_buffer@%d are same. gem_name(%d)",
- wl_resource_get_id(vbuf->resource),
- wl_resource_get_id(comp_buffer->resource), vbuf->names[0]);
- return;
- }
- }
-}
-
-static void
-_e_video_pp_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
-{
- E_Video *video = data;
-
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
-
- if (video->current_fb == vbuf)
- video->current_fb = NULL;
-
- video->committed_list = eina_list_remove(video->committed_list, vbuf);
-
- video->waiting_list = eina_list_remove(video->waiting_list, vbuf);
-
- video->pp_buffer_list = eina_list_remove(video->pp_buffer_list, vbuf);
-}
-
-static E_Comp_Wl_Video_Buf *
-_e_video_pp_buffer_get(E_Video *video, int width, int height)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l;
- int i = 0;
- int aligned_width;
-
- if (video->video_align != -1)
- aligned_width = ROUNDUP(width, video->video_align);
- else
- aligned_width = width;
-
- if (video->pp_buffer_list)
- {
- vbuf = eina_list_data_get(video->pp_buffer_list);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
-
- /* if we need bigger pp_buffers, destroy all pp_buffers and create */
- if (aligned_width > vbuf->width_from_pitch || height != vbuf->height)
- {
- Eina_List *ll;
-
- VIN("pp buffer changed: %dx%d => %dx%d",
- vbuf->width_from_pitch, vbuf->height,
- aligned_width, height);
-
- EINA_LIST_FOREACH_SAFE(video->pp_buffer_list, l, ll, vbuf)
- {
- /* free forcely */
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
- e_comp_wl_video_buffer_unref(vbuf);
- }
- if (video->pp_buffer_list)
- NEVER_GET_HERE();
-
- if (video->waiting_list)
- NEVER_GET_HERE();
- }
- }
-
- if (!video->pp_buffer_list)
- {
- for (i = 0; i < BUFFER_MAX_COUNT; i++)
- {
- vbuf = e_comp_wl_video_buffer_alloc(aligned_width, height, video->pp_tbmfmt, EINA_TRUE);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
-
- e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_pp_buffer_cb_free, video);
- video->pp_buffer_list = eina_list_append(video->pp_buffer_list, vbuf);
-
- }
-
- VIN("pp buffer created: %dx%d, %c%c%c%c",
- vbuf->width_from_pitch, height, FOURCC_STR(video->pp_tbmfmt));
-
- video->next_buffer = video->pp_buffer_list;
- }
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(video->pp_buffer_list, NULL);
- EINA_SAFETY_ON_NULL_RETURN_VAL(video->next_buffer, NULL);
-
- l = video->next_buffer;
- while ((vbuf = video->next_buffer->data))
- {
- video->next_buffer = (video->next_buffer->next) ? video->next_buffer->next : video->pp_buffer_list;
-
- if (!vbuf->in_use)
- return vbuf;
-
- if (l == video->next_buffer)
- {
- VWR("all video framebuffers in use (max:%d)", BUFFER_MAX_COUNT);
- return NULL;
- }
- }
-
- return NULL;
-}
-
-/* convert from logical screen to physical output */
-static void
-_e_video_geometry_cal_physical(E_Video *video)
-{
- E_Zone *zone;
- E_Comp_Wl_Output *output;
- E_Client *topmost;
- int tran, flip;
- int transform;
-
- topmost = e_comp_wl_topmost_parent_get(video->ec);
- EINA_SAFETY_ON_NULL_GOTO(topmost, normal);
-
- output = e_comp_wl_output_find(topmost);
- EINA_SAFETY_ON_NULL_GOTO(output, normal);
-
- zone = e_comp_zone_xy_get(topmost->x, topmost->y);
- EINA_SAFETY_ON_NULL_GOTO(zone, normal);
-
- tran = video->geo.transform & 0x3;
- flip = video->geo.transform & 0x4;
- transform = flip + (tran + output->transform) % 4;
- switch(transform)
- {
- case WL_OUTPUT_TRANSFORM_90:
- video->geo.tdm_transform = TDM_TRANSFORM_270;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- video->geo.tdm_transform = TDM_TRANSFORM_180;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- video->geo.tdm_transform = TDM_TRANSFORM_90;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_270;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_180;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_90;
- break;
- case WL_OUTPUT_TRANSFORM_NORMAL:
- default:
- video->geo.tdm_transform = TDM_TRANSFORM_NORMAL;
- break;
- }
-
- if (output->transform % 2)
- {
- if (video->geo.tdm_transform == TDM_TRANSFORM_FLIPPED)
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_180;
- else if (video->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_90)
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_270;
- else if (video->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_180)
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED;
- else if (video->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_270)
- video->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_90;
- }
-
- if (output->transform == 0)
- video->geo.tdm_output_r = video->geo.output_r;
- else
- e_comp_wl_rect_convert(zone->w, zone->h, output->transform, 1,
- video->geo.output_r.x, video->geo.output_r.y,
- video->geo.output_r.w, video->geo.output_r.h,
- &video->geo.tdm_output_r.x, &video->geo.tdm_output_r.y,
- &video->geo.tdm_output_r.w, &video->geo.tdm_output_r.h);
-
- VDB("geomtry: screen(%d,%d %dx%d | %d) => %d => physical(%d,%d %dx%d | %d)",
- EINA_RECTANGLE_ARGS(&video->geo.output_r), video->geo.transform, transform,
- EINA_RECTANGLE_ARGS(&video->geo.tdm_output_r), video->geo.tdm_transform);
-
- return;
-normal:
- video->geo.tdm_output_r = video->geo.output_r;
- video->geo.tdm_transform = video->geo.transform;
-}
-
-static Eina_Bool
-_e_video_geometry_cal_viewport(E_Video *video)
-{
- E_Client *ec = video->ec;
- E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
- E_Comp_Wl_Subsurf_Data *sdata;
- int x1, y1, x2, y2;
- int tx1, ty1, tx2, ty2;
- E_Comp_Wl_Buffer *comp_buffer;
- tbm_surface_h tbm_surf;
- uint32_t size = 0, offset = 0, pitch = 0;
- int bw, bh;
- int width_from_buffer, height_from_buffer;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
-
- comp_buffer = e_pixmap_resource_get(video->ec->pixmap);
- EINA_SAFETY_ON_NULL_RETURN_VAL(comp_buffer, EINA_FALSE);
-
- tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
- EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surf, EINA_FALSE);
-
- tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
-
- /* input geometry */
- if (IS_RGB(video->tbmfmt))
- video->geo.input_w = pitch / 4;
- else
- video->geo.input_w = pitch;
-
- video->geo.input_h = tbm_surface_get_height(tbm_surf);
-
- bw = tbm_surface_get_width(tbm_surf);
- bh = tbm_surface_get_height(tbm_surf);
-
- switch (vp->buffer.transform)
- {
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- width_from_buffer = bh / vp->buffer.scale;
- height_from_buffer = bw / vp->buffer.scale;
- break;
- default:
- width_from_buffer = bw / vp->buffer.scale;
- height_from_buffer = bh / vp->buffer.scale;
- break;
- }
-
-
- if (vp->buffer.src_width == wl_fixed_from_int(-1))
- {
- x1 = 0.0;
- y1 = 0.0;
- x2 = width_from_buffer;
- y2 = height_from_buffer;
- }
- else
- {
- x1 = wl_fixed_to_int(vp->buffer.src_x);
- y1 = wl_fixed_to_int(vp->buffer.src_y);
- x2 = wl_fixed_to_int(vp->buffer.src_x + vp->buffer.src_width);
- y2 = wl_fixed_to_int(vp->buffer.src_y + vp->buffer.src_height);
- }
-
-#if 0
- VDB("transform(%d) scale(%d) buffer(%dx%d) src(%d,%d %d,%d) viewport(%dx%d)",
- vp->buffer.transform, vp->buffer.scale,
- width_from_buffer, height_from_buffer,
- x1, y1, x2 - x1, y2 - y1,
- ec->comp_data->width_from_viewport, ec->comp_data->height_from_viewport);
-#endif
-
- buffer_transform(width_from_buffer, height_from_buffer,
- vp->buffer.transform, vp->buffer.scale, x1, y1, &tx1, &ty1);
- buffer_transform(width_from_buffer, height_from_buffer,
- vp->buffer.transform, vp->buffer.scale, x2, y2, &tx2, &ty2);
-
- video->geo.input_r.x = (tx1 <= tx2) ? tx1 : tx2;
- video->geo.input_r.y = (ty1 <= ty2) ? ty1 : ty2;
- video->geo.input_r.w = (tx1 <= tx2) ? tx2 - tx1 : tx1 - tx2;
- video->geo.input_r.h = (ty1 <= ty2) ? ty2 - ty1 : ty1 - ty2;
-
- /* output geometry */
- if ((sdata = ec->comp_data->sub.data))
- {
- if (sdata->parent)
- {
- video->geo.output_r.x = sdata->parent->x + sdata->position.x;
- video->geo.output_r.y = sdata->parent->y + sdata->position.y;
- }
- else
- {
- video->geo.output_r.x = sdata->position.x;
- video->geo.output_r.y = sdata->position.y;
- }
- }
- else
- {
- video->geo.output_r.x = ec->x;
- video->geo.output_r.y = ec->y;
- }
-
- video->geo.output_r.w = ec->comp_data->width_from_viewport;
- video->geo.output_r.w = (video->geo.output_r.w + 1) & ~1;
- video->geo.output_r.h = ec->comp_data->height_from_viewport;
-
- e_comp_object_frame_xy_unadjust(ec->frame,
- video->geo.output_r.x, video->geo.output_r.y,
- &video->geo.output_r.x, &video->geo.output_r.y);
- e_comp_object_frame_wh_unadjust(ec->frame,
- video->geo.output_r.w, video->geo.output_r.h,
- &video->geo.output_r.w, &video->geo.output_r.h);
-
- video->geo.transform = vp->buffer.transform;
-
- _e_video_geometry_cal_physical(video);
-
-#if 0
- VDB("geometry(%dx%d %d,%d %dx%d %d,%d %dx%d %d)",
- video->geo.input_w, video->geo.input_h,
- EINA_RECTANGLE_ARGS(&video->geo.input_r),
- EINA_RECTANGLE_ARGS(&video->geo.output_r),
- video->geo.transform);
-#endif
-
- return EINA_TRUE;
-}
-
-static Eina_Bool
-_e_video_geometry_cal_map(E_Video *video)
-{
- E_Client *ec;
- const Evas_Map *m;
- Evas_Coord x1, x2, y1, y2;
- Eina_Rectangle output_r;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(video, EINA_FALSE);
-
- ec = video->ec;
- EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
- EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
-
- m = evas_object_map_get(ec->frame);
- if (!m) return EINA_TRUE;
-
- /* If frame has map, it means that ec's geometry is decided by map's geometry.
- * ec->x,y,w,h and ec->client.x,y,w,h is not useful.
- */
-
- evas_map_point_coord_get(m, 0, &x1, &y1, NULL);
- evas_map_point_coord_get(m, 2, &x2, &y2, NULL);
-
- output_r.x = x1;
- output_r.y = y1;
- output_r.w = x2 - x1;
- output_r.w = (output_r.w + 1) & ~1;
- output_r.h = y2 - y1;
- output_r.h = (output_r.h + 1) & ~1;
-
- if (!memcmp(&video->geo.output_r, &output_r, sizeof(Eina_Rectangle)))
- return EINA_FALSE;
-
- VDB("frame(%p) m(%p) output(%d,%d %dx%d) => (%d,%d %dx%d)", ec->frame, m,
- EINA_RECTANGLE_ARGS(&video->geo.output_r), EINA_RECTANGLE_ARGS(&output_r));
-
- video->geo.output_r = output_r;
-
- _e_video_geometry_cal_physical(video);
-
- return EINA_TRUE;
-}
-
-static void
-_e_video_geometry_cal_to_input(int output_w, int output_h, int input_w, int input_h,
- uint32_t trasnform, int ox, int oy, int *ix, int *iy)
-{
- float ratio_w, ratio_h;
-
- switch(trasnform)
- {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- default:
- *ix = ox, *iy = oy;
- break;
- case WL_OUTPUT_TRANSFORM_270:
- *ix = oy, *iy = output_w - ox;
- break;
- case WL_OUTPUT_TRANSFORM_180:
- *ix = output_w - ox, *iy = output_h - oy;
- break;
- case WL_OUTPUT_TRANSFORM_90:
- *ix = output_h - oy, *iy = ox;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- *ix = output_w - ox, *iy = oy;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- *ix = oy, *iy = ox;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- *ix = ox, *iy = output_h - oy;
- break;
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- *ix = output_h - oy, *iy = output_w - ox;
- break;
- }
- if (trasnform & 0x1)
- {
- ratio_w = (float)input_w / output_h;
- ratio_h = (float)input_h / output_w;
- }
- else
- {
- ratio_w = (float)input_w / output_w;
- ratio_h = (float)input_h / output_h;
- }
- *ix *= ratio_w;
- *iy *= ratio_h;
-}
-
-static void
-_e_video_geometry_cal_to_input_rect(E_Video * video, Eina_Rectangle *srect, Eina_Rectangle *drect)
-{
- int xf1, yf1, xf2, yf2;
-
- /* first transform box coordinates if the scaler is set */
-
- xf1 = srect->x;
- yf1 = srect->y;
- xf2 = srect->x + srect->w;
- yf2 = srect->y + srect->h;
-
- _e_video_geometry_cal_to_input(video->geo.output_r.w, video->geo.output_r.h,
- video->geo.input_r.w, video->geo.input_r.h,
- video->geo.transform, xf1, yf1, &xf1, &yf1);
- _e_video_geometry_cal_to_input(video->geo.output_r.w, video->geo.output_r.h,
- video->geo.input_r.w, video->geo.input_r.h,
- video->geo.transform, xf2, yf2, &xf2, &yf2);
-
- drect->x = MIN(xf1, xf2);
- drect->y = MIN(yf1, yf2);
- drect->w = MAX(xf1, xf2) - drect->x;
- drect->h = MAX(yf1, yf2) - drect->y;
-}
-
-static Eina_Bool
-_e_video_geometry_cal(E_Video * video)
-{
- Eina_Rectangle screen = {0,};
- Eina_Rectangle output_r = {0,}, input_r = {0,};
- const tdm_output_mode *mode = NULL;
- tdm_error tdm_err = TDM_ERROR_NONE;
-
- /* get geometry information with buffer scale, transform and viewport. */
- if (!_e_video_geometry_cal_viewport(video))
- return EINA_FALSE;
-
- _e_video_geometry_cal_map(video);
-
- if (e_config->eom_enable == EINA_TRUE && video->external_video)
- {
- tdm_err = tdm_output_get_mode(video->output, &mode);
- if (tdm_err != TDM_ERROR_NONE)
- return EINA_FALSE;
-
- if (mode == NULL)
- return EINA_FALSE;
-
- screen.w = mode->hdisplay;
- screen.h = mode->vdisplay;
- }
- else
- {
- E_Zone *zone;
- E_Client *topmost;
-
- topmost = e_comp_wl_topmost_parent_get(video->ec);
- EINA_SAFETY_ON_NULL_RETURN_VAL(topmost, EINA_FALSE);
-
- zone = e_comp_zone_xy_get(topmost->x, topmost->y);
- EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
-
- screen.w = zone->w;
- screen.h = zone->h;
- }
-
- e_comp_wl_video_buffer_size_get(video->ec, &input_r.w, &input_r.h);
- // when topmost is not mapped, input size can be abnormal.
- // in this case, it will be render by topmost showing.
- if (!eina_rectangle_intersection(&video->geo.input_r, &input_r) || (video->geo.input_r.w <= 10 || video->geo.input_r.h <= 10))
- {
- VER("input area is empty");
- return EINA_FALSE;
- }
-
- if (video->geo.output_r.x >= 0 && video->geo.output_r.y >= 0 &&
- (video->geo.output_r.x + video->geo.output_r.w) <= screen.w &&
- (video->geo.output_r.y + video->geo.output_r.h) <= screen.h)
- return EINA_TRUE;
-
- /* TODO: need to improve */
-
- output_r = video->geo.output_r;
- if (!eina_rectangle_intersection(&output_r, &screen))
- {
- VER("output_r(%d,%d %dx%d) screen(%d,%d %dx%d) => intersect(%d,%d %dx%d)",
- EINA_RECTANGLE_ARGS(&video->geo.output_r),
- EINA_RECTANGLE_ARGS(&screen), EINA_RECTANGLE_ARGS(&output_r));
- return EINA_TRUE;
- }
-
- output_r.x -= video->geo.output_r.x;
- output_r.y -= video->geo.output_r.y;
-
- if (output_r.w <= 0 || output_r.h <= 0)
- {
- VER("output area is empty");
- return EINA_FALSE;
- }
-
- VDB("output(%d,%d %dx%d) input(%d,%d %dx%d)",
- EINA_RECTANGLE_ARGS(&output_r), EINA_RECTANGLE_ARGS(&input_r));
-
- _e_video_geometry_cal_to_input_rect(video, &output_r, &input_r);
-
- VDB("output(%d,%d %dx%d) input(%d,%d %dx%d)",
- EINA_RECTANGLE_ARGS(&output_r), EINA_RECTANGLE_ARGS(&input_r));
-
- output_r.x += video->geo.output_r.x;
- output_r.y += video->geo.output_r.y;
-
- input_r.x += video->geo.input_r.x;
- input_r.y += video->geo.input_r.y;
-
- output_r.x = output_r.x & ~1;
- output_r.w = (output_r.w + 1) & ~1;
-
- input_r.x = input_r.x & ~1;
- input_r.w = (input_r.w + 1) & ~1;
-
- video->geo.output_r = output_r;
- video->geo.input_r = input_r;
-
- _e_video_geometry_cal_physical(video);
-
- return EINA_TRUE;
-}
-
-static void
-_e_video_format_info_get(E_Video *video)
-{
- E_Comp_Wl_Buffer *comp_buffer;
- tbm_surface_h tbm_surf;
-
- comp_buffer = e_pixmap_resource_get(video->ec->pixmap);
- EINA_SAFETY_ON_NULL_RETURN(comp_buffer);
-
- tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
- EINA_SAFETY_ON_NULL_RETURN(tbm_surf);
-
- video->tbmfmt = tbm_surface_get_format(tbm_surf);
-}
-
-static Eina_Bool
-_e_video_can_commit(E_Video *video)
-{
- if (e_config->eom_enable == EINA_TRUE)
- {
- if (!video->external_video && e_output_dpms_get(video->e_output))
- return EINA_FALSE;
- }
- else
- if (e_output_dpms_get(video->e_output))
- return EINA_FALSE;
-
- if (!_e_video_is_visible(video))
- return EINA_FALSE;
-
- return EINA_TRUE;
-}
-
-static void
-_e_video_commit_handler(tdm_layer *layer, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec,
- void *user_data)
-{
- E_Video *video;
- Eina_List *l;
- E_Comp_Wl_Video_Buf *vbuf;
-
- EINA_LIST_FOREACH(video_list, l, video)
- {
- if (video == user_data) break;
- }
-
- if (!video) return;
- if (!video->committed_list) return;
-
- if (_e_video_can_commit(video))
- {
- tbm_surface_h displaying_buffer = _e_video_layer_get_displaying_buffer(video->layer, NULL);
-
- EINA_LIST_FOREACH(video->committed_list, l, vbuf)
- {
- if (vbuf->tbm_surface == displaying_buffer) break;
- }
- if (!vbuf) return;
- }
- else
- vbuf = eina_list_nth(video->committed_list, 0);
-
- video->committed_list = eina_list_remove(video->committed_list, vbuf);
-
- /* client can attachs the same wl_buffer twice. */
- if (video->current_fb && VBUF_IS_VALID(video->current_fb) && vbuf != video->current_fb)
- {
- e_comp_wl_video_buffer_set_use(video->current_fb, EINA_FALSE);
-
- if (video->current_fb->comp_buffer)
- e_comp_wl_buffer_reference(&video->current_fb->buffer_ref, NULL);
- }
-
- video->current_fb = vbuf;
-
- VDB("current_fb(%d)", MSTAMP(video->current_fb));
-}
-
-static void
-_e_video_commit_buffer(E_Video *video, E_Comp_Wl_Video_Buf *vbuf)
-{
- video->committed_list = eina_list_append(video->committed_list, vbuf);
-
- if (!_e_video_can_commit(video))
- goto no_commit;
-
- if (!_e_video_frame_buffer_show(video, vbuf))
- goto no_commit;
-
- return;
-
-no_commit:
- _e_video_commit_handler(NULL, 0, 0, 0, video);
- _e_video_vblank_handler(NULL, 0, 0, 0, video);
-}
-
-static void
-_e_video_commit_from_waiting_list(E_Video *video)
-{
- E_Comp_Wl_Video_Buf *vbuf;
-
- vbuf = eina_list_nth(video->waiting_list, 0);
- video->waiting_list = eina_list_remove(video->waiting_list, vbuf);
-
- _e_video_commit_buffer(video, vbuf);
-}
-
-EINTERN void
-e_comp_wl_video_hwc_window_commit_data_release(E_Hwc_Window *hwc_window, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec)
-{
- E_Client *ec = NULL;
- E_Video *video = NULL;
- Eina_List *l = NULL;
- E_Video_Layer *video_layer;
-
- EINA_SAFETY_ON_NULL_RETURN(hwc_window);
-
- ec = hwc_window->ec;
- EINA_SAFETY_ON_NULL_RETURN(ec);
-
- EINA_LIST_FOREACH(video_list, l, video)
- if (video->ec == ec) break;
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- video_layer = video->layer;
- EINA_SAFETY_ON_NULL_RETURN(video_layer);
-
- _e_video_commit_handler(NULL, sequence, tv_sec, tv_usec, video);
-}
-
-EINTERN tbm_surface_h
-e_comp_wl_video_hwc_widow_surface_get(E_Hwc_Window *hwc_window)
-{
- E_Client *ec = NULL;
- Eina_List *l = NULL;
- E_Video *video = NULL;
- E_Video_Layer *video_layer;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, NULL);
-
- if (!e_hwc_window_is_video(hwc_window))
- {
- ERR("ehw:%p is NOT Video HWC window.", hwc_window);
- return NULL;
- }
-
- ec = hwc_window->ec;
- if (!ec) return NULL;
-
- EINA_LIST_FOREACH(video_list, l, video)
- if (video->ec == ec) break;
- EINA_SAFETY_ON_NULL_RETURN_VAL(video, NULL);
-
- video_layer = video->layer;
- EINA_SAFETY_ON_NULL_RETURN_VAL(video_layer, NULL);
-
- return video_layer->cur_tsurface;
-}
-
-EINTERN Eina_Bool
-e_comp_wl_video_hwc_window_info_get(E_Hwc_Window *hwc_window, tdm_hwc_window_info *hwc_win_info)
-{
- E_Client *ec = NULL;
- Eina_List *l = NULL;
- E_Video *video = NULL;
- E_Video_Layer *video_layer;
- E_Video_Info_Layer *vinfo;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
-
- if (!e_hwc_window_is_video(hwc_window))
- {
- ERR("ehw:%p is NOT Video HWC window.", hwc_window);
- return EINA_FALSE;
- }
-
- ec = hwc_window->ec;
- EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
-
- EINA_LIST_FOREACH(video_list, l, video)
- if (video->ec == ec) break;
- EINA_SAFETY_ON_NULL_RETURN_VAL(video,EINA_FALSE);
-
- video_layer = video->layer;
- EINA_SAFETY_ON_NULL_RETURN_VAL(video_layer, EINA_FALSE);
-
- vinfo = &video_layer->info;
- EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, EINA_FALSE);
-
- memcpy(&hwc_win_info->src_config, &vinfo->src_config, sizeof(tdm_info_config));
- memcpy(&hwc_win_info->dst_pos, &vinfo->dst_pos, sizeof(tdm_pos));
- hwc_win_info->transform = vinfo->transform;
-
- return EINA_TRUE;
-}
-
-static void
-_e_video_vblank_handler(tdm_output *output, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec,
- void *user_data)
-{
- E_Video *video;
- Eina_List *l;
-
- EINA_LIST_FOREACH(video_list, l, video)
- {
- if (video == user_data) break;
- }
-
- if (!video) return;
-
- video->waiting_vblank = EINA_FALSE;
-
- if (video->video_plane_ready_handler) return;
-
- if (video->waiting_list)
- _e_video_commit_from_waiting_list(video);
-}
-
-static void
-_e_video_video_set_hook(void *data, E_Plane *plane)
-{
- E_Video *video = (E_Video *)data;
-
- if (video->e_plane != plane) return;
- if (video->waiting_vblank) return;
-
- if (video->waiting_list)
- _e_video_commit_from_waiting_list(video);
-
- E_FREE_FUNC(video->video_plane_ready_handler, e_plane_hook_del);
-}
-
-static Eina_Bool
-_e_video_frame_buffer_show(E_Video *video, E_Comp_Wl_Video_Buf *vbuf)
-{
- E_Video_Info_Layer info, old_info;
- tdm_error ret;
- E_Client *topmost;
- Tdm_Prop_Value *prop;
-
- if (!vbuf)
- {
- if (video->layer)
- {
- VIN("unset layer: hide");
- _e_video_set_layer(video, EINA_FALSE);
- }
- return EINA_TRUE;
- }
-
- if (!video->layer)
- {
- VIN("set layer: show");
- if (!_e_video_set_layer(video, EINA_TRUE))
- {
- VER("set layer failed");
- return EINA_FALSE;
- }
- // need call tdm property in list
- Tdm_Prop_Value *prop;
- EINA_LIST_FREE(video->tdm_prop_list, prop)
- {
- VIN("call property(%s), value(%d)", prop->name, (unsigned int)prop->value.u32);
- _e_video_layer_set_property(video->layer, prop);
- free(prop);
- }
- }
-
- CLEAR(old_info);
- ret = _e_video_layer_get_info(video->layer, &old_info);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
-
- CLEAR(info);
- info.src_config.size.h = vbuf->width_from_pitch;
- info.src_config.size.v = vbuf->height_from_size;
- info.src_config.pos.x = vbuf->content_r.x;
- info.src_config.pos.y = vbuf->content_r.y;
- info.src_config.pos.w = vbuf->content_r.w;
- info.src_config.pos.h = vbuf->content_r.h;
- info.src_config.format = vbuf->tbmfmt;
- info.dst_pos.x = video->geo.tdm_output_r.x;
- info.dst_pos.y = video->geo.tdm_output_r.y;
- info.dst_pos.w = video->geo.tdm_output_r.w;
- info.dst_pos.h = video->geo.tdm_output_r.h;
- info.transform = vbuf->content_t;
-
- if (memcmp(&old_info, &info, sizeof(tdm_info_layer)))
- {
- ret = _e_video_layer_set_info(video->layer, &info);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
- }
-
- ret = _e_video_layer_set_buffer(video->layer, vbuf->tbm_surface);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
-
- ret = _e_video_layer_commit(video->layer, _e_video_commit_handler, video);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
-
- ret = tdm_output_wait_vblank(video->output, 1, 0, _e_video_vblank_handler, video);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
-
- video->waiting_vblank = EINA_TRUE;
-
- EINA_LIST_FREE(video->late_tdm_prop_list, prop)
- {
- VIN("call property(%s), value(%d)", prop->name, (unsigned int)prop->value.u32);
- _e_video_layer_set_property(video->layer, prop);
- free(prop);
- }
-
- topmost = e_comp_wl_topmost_parent_get(video->ec);
- if (topmost && topmost->argb && !e_comp_object_mask_has(video->ec->frame))
- {
- Eina_Bool do_punch = EINA_TRUE;
-
- /* FIXME: the mask obj can be drawn at the wrong position in the beginnig
- * time. It happens caused by window manager policy.
- */
- if ((topmost->fullscreen || topmost->maximized) &&
- (video->geo.output_r.x == 0 || video->geo.output_r.y == 0))
- {
- int bw, bh;
-
- e_pixmap_size_get(topmost->pixmap, &bw, &bh);
-
- if (bw > 100 && bh > 100 &&
- video->geo.output_r.w < 100 && video->geo.output_r.h < 100)
- {
- VIN("don't punch. (%dx%d, %dx%d)",
- bw, bh, video->geo.output_r.w, video->geo.output_r.h);
- do_punch = EINA_FALSE;
- }
- }
-
- if (do_punch)
- {
- e_comp_object_mask_set(video->ec->frame, EINA_TRUE);
- VIN("punched");
- }
- }
-
- if (video_punch)
- {
- e_comp_object_mask_set(video->ec->frame, EINA_TRUE);
- VIN("punched");
- }
-
- VDT("Client(%s):PID(%d) RscID(%d), Buffer(%p, refcnt:%d) is shown."
- "Geometry details are : buffer size(%dx%d) src(%d,%d, %dx%d)"
- " dst(%d,%d, %dx%d), transform(%d)",
- e_client_util_name_get(video->ec) ?: "No Name" , video->ec->netwm.pid,
- wl_resource_get_id(video->surface), vbuf, vbuf->ref_cnt,
- info.src_config.size.h, info.src_config.size.v, info.src_config.pos.x,
- info.src_config.pos.y, info.src_config.pos.w, info.src_config.pos.h,
- info.dst_pos.x, info.dst_pos.y, info.dst_pos.w, info.dst_pos.h, info.transform);
-
-
- return EINA_TRUE;
-}
-
-static void
-_e_video_buffer_show(E_Video *video, E_Comp_Wl_Video_Buf *vbuf, unsigned int transform)
-{
- vbuf->content_t = transform;
-
- e_comp_wl_video_buffer_set_use(vbuf, EINA_TRUE);
-
- if (vbuf->comp_buffer)
- e_comp_wl_buffer_reference(&vbuf->buffer_ref, vbuf->comp_buffer);
-
- if (video->waiting_vblank || video->video_plane_ready_handler)
- {
- video->waiting_list = eina_list_append(video->waiting_list, vbuf);
- VDB("There are waiting fbs more than 1");
- return;
- }
-
- _e_video_commit_buffer(video, vbuf);
-}
-
-static void
-_e_video_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
-{
- E_Video *video = data;
-
- if (_e_video_geometry_cal_map(video))
- _e_video_render(video, __FUNCTION__);
-}
-
-static void
-_e_video_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
-{
- E_Video *video = data;
-
- if (_e_video_geometry_cal_map(video))
- _e_video_render(video, __FUNCTION__);
-}
-
-static void
-_e_video_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
-{
- E_Video *video = data;
-
- if (e_object_is_del(E_OBJECT(video->ec))) return;
-
- if (!video->ec->comp_data->video_client)
- return;
-
- if (video->need_force_render)
- {
- VIN("video forcely rendering..");
- _e_video_render(video, __FUNCTION__);
- }
-
- /* if stand_alone is true, not show */
- if ((video->ec->comp_data->sub.data && video->ec->comp_data->sub.data->stand_alone) ||
- (video->ec->comp_data->sub.data && video->follow_topmost_visibility))
- {
-#if 0 //mute off is managed by client. mute off in server made many issues.
- if (!video->layer) return;
-
- if (video->tdm_mute_id != -1)
- {
- Tdm_Prop_Value prop = {.id = video->tdm_mute_id, .value.u32 = 0};
- VIN("video surface show. mute off (ec:%p)", video->ec);
- _e_video_layer_set_property(video->layer, &prop);
- }
-#endif
- return;
- }
-
- if (!video->layer)
- {
- VIN("set layer: show");
- if (!_e_video_set_layer(video, EINA_TRUE))
- {
- VER("set layer failed");
- return;
- }
- // need call tdm property in list
- Tdm_Prop_Value *prop;
- EINA_LIST_FREE(video->tdm_prop_list, prop)
- {
- VIN("call property(%s), value(%d)", prop->name, (unsigned int)prop->value.u32);
- _e_video_layer_set_property(video->layer, prop);
- free(prop);
- }
- }
-
- VIN("evas show (ec:%p)", video->ec);
- if (video->current_fb)
- _e_video_buffer_show(video, video->current_fb, video->current_fb->content_t);
-}
-
-static void
-_e_video_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
-{
- E_Video *video = data;
-
- if (e_object_is_del(E_OBJECT(video->ec))) return;
-
- if (!video->ec->comp_data->video_client)
- return;
-
- /* if stand_alone is true, not hide */
- if (video->ec->comp_data->sub.data && video->ec->comp_data->sub.data->stand_alone)
- {
- if (!video->layer) return;
-
- if (video->tdm_mute_id != -1)
- {
- Tdm_Prop_Value prop = {.id = video->tdm_mute_id, .value.u32 = 1};
- VIN("video surface hide. mute on (ec:%p)", video->ec);
- _e_video_layer_set_property(video->layer, &prop);
- }
- return;
- }
-
- VIN("evas hide (ec:%p)", video->ec);
- _e_video_frame_buffer_show(video, NULL);
-}
-
-static E_Video *
-_e_video_create(struct wl_resource *video_object, struct wl_resource *surface)
-{
- E_Video *video;
- E_Client *ec;
-
- ec = wl_resource_get_user_data(surface);
- EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
- EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(ec)), NULL);
-
- video = calloc(1, sizeof *video);
- EINA_SAFETY_ON_NULL_RETURN_VAL(video, NULL);
-
- video->video_object = video_object;
- video->surface = surface;
- video->output_align = -1;
- video->pp_align = -1;
- video->video_align = -1;
- video->tdm_mute_id = -1;
-
- VIN("create. ec(%p) wl_surface@%d", ec, wl_resource_get_id(video->surface));
-
- video_list = eina_list_append(video_list, video);
-
- _e_video_set(video, ec);
-
- return video;
-}
-
-static void
-_e_video_set(E_Video *video, E_Client *ec)
-{
- int ominw = -1, ominh = -1, omaxw = -1, omaxh = -1;
- int i, count = 0;
- const tdm_prop *props;
-
- video->ec = ec;
- video->window = e_client_util_win_get(ec);
-
- evas_object_event_callback_add(video->ec->frame, EVAS_CALLBACK_HIDE,
- _e_video_cb_evas_hide, video);
- evas_object_event_callback_add(video->ec->frame, EVAS_CALLBACK_SHOW,
- _e_video_cb_evas_show, video);
-
- if (e_config->eom_enable == EINA_TRUE)
- {
- video->external_video = e_eom_is_ec_external(ec);
- if (video->external_video)
- {
- tdm_error ret;
- unsigned int index = 0;
-
- video->output = e_eom_tdm_output_by_ec_get(ec);
- EINA_SAFETY_ON_NULL_RETURN(video->output);
-
- ret = tdm_output_get_pipe(video->output, &index);
- EINA_SAFETY_ON_FALSE_RETURN(ret == TDM_ERROR_NONE);
-
- video->e_output = e_output_find_by_index(index);
- EINA_SAFETY_ON_NULL_RETURN(video->e_output);
-
- ec->comp_data->video_client = 1;
-
- return;
- }
- }
-
- EINA_SAFETY_ON_NULL_RETURN(video->ec->zone);
-
- video->e_output = e_output_find(video->ec->zone->output_id);
- EINA_SAFETY_ON_NULL_RETURN(video->e_output);
-
- video->output = video->e_output->toutput;
- EINA_SAFETY_ON_NULL_RETURN(video->output);
-
- if (video_to_primary)
- {
- VIN("show video to primary layer");
- ec->comp_data->video_client = 0;
- e_policy_animatable_lock(ec, E_POLICY_ANIMATABLE_NEVER, 1);
- }
- else if (_e_video_tdm_output_has_video_layer(video->output))
- {
- /* If tdm offers video layers, we will assign a tdm layer when showing */
- VIN("video client");
- ec->comp_data->video_client = 1;
- }
- else
- {
- /* If tdm doesn't offer video layers, we assign a tdm layer now. If failed,
- * video will be displayed via the UI rendering path.
- */
- if (_e_video_set_layer(video, EINA_TRUE))
- {
- VIN("video client");
- ec->comp_data->video_client = 1;
- }
- else
- {
- VIN("no video client");
- ec->comp_data->video_client = 0;
- e_policy_animatable_lock(ec, E_POLICY_ANIMATABLE_NEVER, 1);
- }
- }
-
- tdm_output_get_available_size(video->output, &ominw, &ominh, &omaxw, &omaxh, &video->output_align);
-
- if (!e_comp_screen_pp_support())
- {
- video->video_align = video->output_align;
- tizen_video_object_send_size(video->video_object,
- ominw, ominh, omaxw, omaxh, video->output_align);
- }
- else
- {
- int minw = -1, minh = -1, maxw = -1, maxh = -1;
- int pminw = -1, pminh = -1, pmaxw = -1, pmaxh = -1;
-
- tdm_display_get_pp_available_size(e_comp->e_comp_screen->tdisplay, &pminw, &pminh, &pmaxw, &pmaxh, &video->pp_align);
-
- minw = MAX(ominw, pminw);
- minh = MAX(ominh, pminh);
-
- if (omaxw != -1 && pmaxw == -1)
- maxw = omaxw;
- else if (omaxw == -1 && pmaxw != -1)
- maxw = pmaxw;
- else
- maxw = MIN(omaxw, pmaxw);
-
- if (omaxh != -1 && pmaxh == -1)
- maxh = omaxh;
- else if (omaxh == -1 && pmaxh != -1)
- maxh = pmaxh;
- else
- maxh = MIN(omaxh, pmaxh);
-
- if (video->output_align != -1 && video->pp_align == -1)
- video->video_align = video->output_align;
- else if (video->output_align == -1 && video->pp_align != -1)
- video->video_align = video->pp_align;
- else if (video->output_align == -1 && video->pp_align == -1)
- video->video_align = video->pp_align;
- else if (video->output_align > 0 && video->pp_align > 0)
- video->video_align = lcm(video->output_align, video->pp_align);
- else
- ERR("invalid align: %d, %d", video->output_align, video->pp_align);
-
- tizen_video_object_send_size(video->video_object,
- minw, minh, maxw, maxh, video->video_align);
- VIN("align width: output(%d) pp(%d) video(%d)",
- video->output_align, video->pp_align, video->video_align);
- }
-
- _e_video_layer_get_available_properties(video->layer, &props, &count);
- for (i = 0; i < count; i++)
- {
- tdm_value value;
- _e_video_layer_get_property(video->layer, props[i].id, &value);
- tizen_video_object_send_attribute(video->video_object, props[i].name, value.u32);
-
- if (!strncmp(props[i].name, "mute", TDM_NAME_LEN))
- video->tdm_mute_id = props[i].id;
- }
-}
-
-static void
-_e_video_hide(E_Video *video)
-{
- E_Comp_Wl_Video_Buf *vbuf;
-
- if (video->current_fb || video->committed_list)
- _e_video_frame_buffer_show(video, NULL);
-
- if (video->current_fb)
- {
- e_comp_wl_video_buffer_set_use(video->current_fb, EINA_FALSE);
- video->current_fb = NULL;
- }
-
- if (video->old_comp_buffer)
- video->old_comp_buffer = NULL;
-
- EINA_LIST_FREE(video->committed_list, vbuf)
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
-
- EINA_LIST_FREE(video->waiting_list, vbuf)
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
-}
-
-static void
-_e_video_destroy(E_Video *video)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l = NULL, *ll = NULL;
-
- if (!video)
- return;
-
- VIN("destroy");
-
- if (video->cb_registered)
- {
- evas_object_event_callback_del_full(video->ec->frame, EVAS_CALLBACK_RESIZE,
- _e_video_cb_evas_resize, video);
- evas_object_event_callback_del_full(video->ec->frame, EVAS_CALLBACK_MOVE,
- _e_video_cb_evas_move, video);
- }
-
- evas_object_event_callback_del_full(video->ec->frame, EVAS_CALLBACK_HIDE,
- _e_video_cb_evas_hide, video);
- evas_object_event_callback_del_full(video->ec->frame, EVAS_CALLBACK_SHOW,
- _e_video_cb_evas_show, video);
-
- wl_resource_set_destructor(video->video_object, NULL);
-
- _e_video_hide(video);
-
- /* others */
- EINA_LIST_FOREACH_SAFE(video->input_buffer_list, l, ll, vbuf)
- {
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
- e_comp_wl_video_buffer_unref(vbuf);
- }
-
- EINA_LIST_FOREACH_SAFE(video->pp_buffer_list, l, ll, vbuf)
- {
- e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
- e_comp_wl_video_buffer_unref(vbuf);
- }
-
- if(video->tdm_prop_list)
- {
- Tdm_Prop_Value *tdm_prop;
- EINA_LIST_FREE(video->tdm_prop_list, tdm_prop)
- {
- free(tdm_prop);
- }
- }
- if(video->late_tdm_prop_list)
- {
- Tdm_Prop_Value *tdm_prop;
- EINA_LIST_FREE(video->late_tdm_prop_list, tdm_prop)
- {
- free(tdm_prop);
- }
- }
-
- if (video->input_buffer_list)
- NEVER_GET_HERE();
- if (video->pp_buffer_list)
- NEVER_GET_HERE();
- if (video->tdm_prop_list)
- NEVER_GET_HERE();
- if (video->late_tdm_prop_list)
- NEVER_GET_HERE();
-
- /* destroy converter second */
- if (video->pp)
- tdm_pp_destroy(video->pp);
-
- if (video->layer)
- {
- VIN("unset layer: destroy");
- _e_video_set_layer(video, EINA_FALSE);
- }
-
- video_list = eina_list_remove(video_list, video);
-
- free(video);
-
-#if 0
- if (e_comp_wl_video_buffer_list_length() > 0)
- e_comp_wl_video_buffer_list_print(NULL);
-#endif
-}
-
-static Eina_Bool
-_e_video_check_if_pp_needed(E_Video *video)
-{
- int i, count = 0;
- const tbm_format *formats;
- Eina_Bool found = EINA_FALSE;
- tdm_layer_capability capabilities = 0;
-
- if (e_hwc_policy_get(video->e_output->hwc) != E_HWC_POLICY_WINDOWS)
- {
- tdm_layer *layer = _e_video_tdm_video_layer_get(video->output);
-
- tdm_layer_get_capabilities(layer, &capabilities);
-
- /* don't need pp if a layer has TDM_LAYER_CAPABILITY_VIDEO capability*/
- if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
- return EINA_FALSE;
-
- /* check formats */
- tdm_layer_get_available_formats(layer, &formats, &count);
- for (i = 0; i < count; i++)
- if (formats[i] == video->tbmfmt)
- {
- found = EINA_TRUE;
- break;
- }
-
- if (!found)
- {
- if (formats && count > 0)
- video->pp_tbmfmt = formats[0];
- else
- {
- WRN("No layer format information!!!");
- video->pp_tbmfmt = TBM_FORMAT_ARGB8888;
- }
- return EINA_TRUE;
- }
-
- if (capabilities & TDM_LAYER_CAPABILITY_SCANOUT)
- goto need_pp;
-
- /* check size */
- if (video->geo.input_r.w != video->geo.output_r.w || video->geo.input_r.h != video->geo.output_r.h)
- if (!(capabilities & TDM_LAYER_CAPABILITY_SCALE))
- goto need_pp;
-
- /* check rotate */
- if (video->geo.transform || e_comp->e_comp_screen->rotation > 0)
- if (!(capabilities & TDM_LAYER_CAPABILITY_TRANSFORM))
- goto need_pp;
- }
- else
- {
- tdm_hwc_capability capabilities = 0;
- tdm_error error;
-
- error = tdm_hwc_get_video_supported_formats(video->e_output->hwc->thwc, &formats, &count);
- if (error != TDM_ERROR_NONE)
- {
- video->pp_tbmfmt = TBM_FORMAT_ARGB8888;
- return EINA_TRUE;
- }
- for (i = 0; i < count; i++)
- if (formats[i] == video->tbmfmt)
- {
- found = EINA_TRUE;
- break;
- }
-
- if (!found)
- {
- video->pp_tbmfmt = TBM_FORMAT_ARGB8888;
- return EINA_TRUE;
- }
-
- error = tdm_hwc_get_capabilities(video->e_output->hwc->thwc, &capabilities);
- if (error != TDM_ERROR_NONE)
- {
- video->pp_tbmfmt = TBM_FORMAT_ARGB8888;
- return EINA_TRUE;
- }
-
- /* check size */
- if (capabilities & TDM_HWC_CAPABILITY_VIDEO_SCANOUT)
- goto need_pp;
-
- if (video->geo.input_r.w != video->geo.output_r.w || video->geo.input_r.h != video->geo.output_r.h)
- if (!(capabilities & TDM_HWC_CAPABILITY_VIDEO_SCALE))
- goto need_pp;
-
- /* check rotate */
- if (video->geo.transform || e_comp->e_comp_screen->rotation > 0)
- if (!(capabilities & TDM_HWC_CAPABILITY_VIDEO_TRANSFORM))
- goto need_pp;
- }
-
- return EINA_FALSE;
-
-need_pp:
- video->pp_tbmfmt = video->tbmfmt;
- return EINA_TRUE;
-}
-
-static void
-_e_video_pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
-{
- E_Video *video = (E_Video*)user_data;
- E_Comp_Wl_Video_Buf *input_buffer, *pp_buffer;
-
- input_buffer = _e_video_vbuf_find(video->input_buffer_list, sb);
- if (input_buffer)
- e_comp_wl_video_buffer_unref(input_buffer);
-
- pp_buffer = _e_video_vbuf_find(video->pp_buffer_list, db);
- if (pp_buffer)
- {
- e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
- if (!_e_video_is_visible(video)) return;
-
- _e_video_buffer_show(video, pp_buffer, 0);
- }
- else
- {
- VER("There is no pp_buffer");
- // there is no way to set in_use flag.
- // This will cause issue when server get available pp_buffer.
- }
-}
-
-static void
-_e_video_render(E_Video *video, const char *func)
-{
- E_Comp_Wl_Buffer *comp_buffer;
- E_Comp_Wl_Video_Buf *pp_buffer = NULL;
- E_Comp_Wl_Video_Buf *input_buffer = NULL;
- E_Client *topmost;
-
- EINA_SAFETY_ON_NULL_RETURN(video->ec);
-
- /* buffer can be NULL when camera/video's mode changed. Do nothing and
- * keep previous frame in this case.
- */
- if (!video->ec->pixmap)
- return;
-
- if (!_e_video_is_visible(video))
- {
- _e_video_hide(video);
- return;
- }
-
- comp_buffer = e_pixmap_resource_get(video->ec->pixmap);
- if (!comp_buffer) return;
-
- _e_video_format_info_get(video);
-
- /* not interested with other buffer type */
- if (!wayland_tbm_server_get_surface(NULL, comp_buffer->resource))
- return;
-
- topmost = e_comp_wl_topmost_parent_get(video->ec);
- EINA_SAFETY_ON_NULL_RETURN(topmost);
-
- if(e_comp_wl_viewport_is_changed(topmost))
- {
- VIN("need update viewport: apply topmost");
- e_comp_wl_viewport_apply(topmost);
- }
-
- if (!_e_video_geometry_cal(video))
- {
- if(!video->need_force_render && !_e_video_parent_is_viewable(video))
- {
- VIN("need force render");
- video->need_force_render = EINA_TRUE;
- }
- return;
- }
-
- if (!memcmp(&video->old_geo, &video->geo, sizeof video->geo) &&
- video->old_comp_buffer == comp_buffer)
- return;
-
- video->need_force_render = EINA_FALSE;
-
- DBG("====================================== (%s)", func);
- VDB("old: "GEO_FMT" buf(%p)", GEO_ARG(&video->old_geo), video->old_comp_buffer);
- VDB("new: "GEO_FMT" buf(%p) %c%c%c%c", GEO_ARG(&video->geo), comp_buffer, FOURCC_STR(video->tbmfmt));
-
- _e_video_input_buffer_valid(video, comp_buffer);
-
- if (!_e_video_check_if_pp_needed(video))
- {
- /* 1. non converting case */
- input_buffer = _e_video_input_buffer_get(video, comp_buffer, EINA_TRUE);
- EINA_SAFETY_ON_NULL_GOTO(input_buffer, render_fail);
-
- _e_video_buffer_show(video, input_buffer, video->geo.tdm_transform);
-
- video->old_geo = video->geo;
- video->old_comp_buffer = comp_buffer;
-
- goto done;
- }
-
- /* 2. converting case */
- if (!video->pp)
- {
- tdm_pp_capability pp_cap;
- tdm_error error = TDM_ERROR_NONE;
-
- video->pp = tdm_display_create_pp(e_comp->e_comp_screen->tdisplay, NULL);
- EINA_SAFETY_ON_NULL_GOTO(video->pp, render_fail);
-
- tdm_display_get_pp_available_size(e_comp->e_comp_screen->tdisplay, &video->pp_minw, &video->pp_minh,
- &video->pp_maxw, &video->pp_maxh, &video->pp_align);
-
- error = tdm_display_get_pp_capabilities(e_comp->e_comp_screen->tdisplay, &pp_cap);
- if (error == TDM_ERROR_NONE)
- {
- if (pp_cap & TDM_PP_CAPABILITY_SCANOUT)
- video->pp_scanout = EINA_TRUE;
- }
- }
-
- if ((video->pp_minw > 0 && (video->geo.input_r.w < video->pp_minw || video->geo.tdm_output_r.w < video->pp_minw)) ||
- (video->pp_minh > 0 && (video->geo.input_r.h < video->pp_minh || video->geo.tdm_output_r.h < video->pp_minh)) ||
- (video->pp_maxw > 0 && (video->geo.input_r.w > video->pp_maxw || video->geo.tdm_output_r.w > video->pp_maxw)) ||
- (video->pp_maxh > 0 && (video->geo.input_r.h > video->pp_maxh || video->geo.tdm_output_r.h > video->pp_maxh)))
- {
- INF("size(%dx%d, %dx%d) is out of PP range",
- video->geo.input_r.w, video->geo.input_r.h, video->geo.tdm_output_r.w, video->geo.tdm_output_r.h);
- goto done;
- }
-
- input_buffer = _e_video_input_buffer_get(video, comp_buffer, EINA_FALSE);
- EINA_SAFETY_ON_NULL_GOTO(input_buffer, render_fail);
-
- pp_buffer = _e_video_pp_buffer_get(video, video->geo.tdm_output_r.w, video->geo.tdm_output_r.h);
- EINA_SAFETY_ON_NULL_GOTO(pp_buffer, render_fail);
-
- if (memcmp(&video->old_geo, &video->geo, sizeof video->geo))
- {
- tdm_info_pp info;
-
- CLEAR(info);
- info.src_config.size.h = input_buffer->width_from_pitch;
- info.src_config.size.v = input_buffer->height_from_size;
- info.src_config.pos.x = video->geo.input_r.x;
- info.src_config.pos.y = video->geo.input_r.y;
- info.src_config.pos.w = video->geo.input_r.w;
- info.src_config.pos.h = video->geo.input_r.h;
- info.src_config.format = video->tbmfmt;
- info.dst_config.size.h = pp_buffer->width_from_pitch;
- info.dst_config.size.v = pp_buffer->height_from_size;
- info.dst_config.pos.w = video->geo.tdm_output_r.w;
- info.dst_config.pos.h = video->geo.tdm_output_r.h;
- info.dst_config.format = video->pp_tbmfmt;
- info.transform = video->geo.tdm_transform;
-
- if (tdm_pp_set_info(video->pp, &info))
- {
- VER("tdm_pp_set_info() failed");
- goto render_fail;
- }
-
- if (tdm_pp_set_done_handler(video->pp, _e_video_pp_cb_done, video))
- {
- VER("tdm_pp_set_done_handler() failed");
- goto render_fail;
- }
-
- CLEAR(video->pp_r);
- video->pp_r.w = info.dst_config.pos.w;
- video->pp_r.h = info.dst_config.pos.h;
- }
-
- pp_buffer->content_r = video->pp_r;
-
- if (tdm_pp_attach(video->pp, input_buffer->tbm_surface, pp_buffer->tbm_surface))
- {
- VER("tdm_pp_attach() failed");
- goto render_fail;
- }
-
- e_comp_wl_video_buffer_set_use(pp_buffer, EINA_TRUE);
-
- e_comp_wl_buffer_reference(&input_buffer->buffer_ref, comp_buffer);
-
- if (tdm_pp_commit(video->pp))
- {
- VER("tdm_pp_commit() failed");
- e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
- goto render_fail;
- }
-
- video->old_geo = video->geo;
- video->old_comp_buffer = comp_buffer;
-
- goto done;
-
-render_fail:
- if (input_buffer)
- e_comp_wl_video_buffer_unref(input_buffer);
-
-done:
- if (!video->cb_registered)
- {
- evas_object_event_callback_add(video->ec->frame, EVAS_CALLBACK_RESIZE,
- _e_video_cb_evas_resize, video);
- evas_object_event_callback_add(video->ec->frame, EVAS_CALLBACK_MOVE,
- _e_video_cb_evas_move, video);
- video->cb_registered = EINA_TRUE;
- }
- DBG("======================================.");
-}
-
-static Eina_Bool
-_e_video_cb_ec_buffer_change(void *data, int type, void *event)
-{
- E_Client *ec;
- E_Event_Client *ev = event;
- E_Video *video;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
- EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
-
- ec = ev->ec;
- if (e_object_is_del(E_OBJECT(ec)))
- return ECORE_CALLBACK_PASS_ON;
-
- /* not interested with non video_surface, */
- video = find_video_with_surface(ec->comp_data->surface);
- if (!video) return ECORE_CALLBACK_PASS_ON;
-
- if (!video->ec->comp_data->video_client)
- return ECORE_CALLBACK_PASS_ON;
-
- if (e_config->eom_enable == EINA_TRUE)
- {
- /* skip external client buffer if its top parent is not current for eom anymore */
- if (video->external_video && e_eom_is_ec_external(ec))
- {
- VWR("skip external buffer");
- return ECORE_CALLBACK_PASS_ON;
- }
- }
-
- _e_video_render(video, __FUNCTION__);
-
- return ECORE_CALLBACK_PASS_ON;
-}
-
-static Eina_Bool
-_e_video_cb_ec_remove(void *data, int type, void *event)
-{
- E_Event_Client *ev = event;
- E_Client *ec;
- E_Video *video;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
- EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
-
- ec = ev->ec;
- if (!ec->comp_data) return ECORE_CALLBACK_PASS_ON;
-
- video = find_video_with_surface(ec->comp_data->surface);
- if (!video) return ECORE_CALLBACK_PASS_ON;
-
- _e_video_destroy(video);
-
- return ECORE_CALLBACK_PASS_ON;
-}
-
-static Eina_Bool
-_e_video_cb_ec_client_show(void *data, int type, void *event)
-{
- E_Event_Client *ev = event;
- E_Client *ec;
- E_Client *video_ec = NULL;
- E_Video *video = NULL;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
- EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
-
- ec = ev->ec;
- if (!ec->comp_data) return ECORE_CALLBACK_PASS_ON;
-
- video_ec = find_video_child_get(ec);
- if (!video_ec) return ECORE_CALLBACK_PASS_ON;
-
- video = find_video_with_surface(video_ec->comp_data->surface);
- if (!video) return ECORE_CALLBACK_PASS_ON;
-
- VIN("client(0x%08"PRIxPTR") show: find video child(0x%08"PRIxPTR")", (Ecore_Window)e_client_util_win_get(ec), (Ecore_Window)e_client_util_win_get(video_ec));
- if(video->old_comp_buffer)
- {
- VIN("video already rendering..");
- return ECORE_CALLBACK_PASS_ON;
- }
-
- if (ec == e_comp_wl_topmost_parent_get(video->ec))
- {
- if (e_config->eom_enable == EINA_TRUE)
- {
- /* skip external client buffer if its top parent is not current for eom anymore */
- if (video->external_video && e_eom_is_ec_external(ec))
- {
- VWR("skip external buffer");
- return ECORE_CALLBACK_PASS_ON;
- }
- }
-
- VIN("video need rendering..");
- e_comp_wl_viewport_apply(ec);
- _e_video_render(video, __FUNCTION__);
- }
-
- return ECORE_CALLBACK_PASS_ON;
-}
-
-static Eina_Bool
-_e_video_cb_ec_visibility_change(void *data, int type, void *event)
-{
- E_Event_Remote_Surface_Provider *ev = event;
- E_Client *ec = ev->ec;
- E_Video *video;
- Eina_List *l;
-
- EINA_LIST_FOREACH(video_list, l, video)
- {
- E_Client *offscreen_parent = find_offscreen_parent_get(video->ec);
- if (!offscreen_parent) continue;
- if (offscreen_parent != ec) continue;
- switch (ec->visibility.obscured)
- {
- case E_VISIBILITY_FULLY_OBSCURED:
- _e_video_cb_evas_hide(video, NULL, NULL, NULL);
- break;
- case E_VISIBILITY_UNOBSCURED:
- _e_video_cb_evas_show(video, NULL, NULL, NULL);
- break;
- default:
- VER("Not implemented");
- return ECORE_CALLBACK_PASS_ON;
- }
- }
-
- return ECORE_CALLBACK_PASS_ON;
-}
-
-static Eina_Bool
-_e_video_cb_topmost_ec_visibility_change(void *data, int type, void *event)
-{
- E_Event_Client *ev = event;
- E_Client *ec = ev->ec;
- E_Video *video;
- Eina_List *l = NULL;
-
- EINA_LIST_FOREACH(video_list, l, video)
- {
- E_Client *topmost = e_comp_wl_topmost_parent_get(video->ec);
- if (!topmost) continue;
- if (topmost == video->ec) continue;
- if (topmost != ec) continue;
- if (video->follow_topmost_visibility)
- {
- switch (ec->visibility.obscured)
- {
- case E_VISIBILITY_FULLY_OBSCURED:
- VIN("follow_topmost_visibility: fully_obscured");
- _e_video_cb_evas_hide(video, NULL, NULL, NULL);
- break;
- case E_VISIBILITY_UNOBSCURED:
- VIN("follow_topmost_visibility: UNOBSCURED");
- _e_video_cb_evas_show(video, NULL, NULL, NULL);
- break;
- default:
- return ECORE_CALLBACK_PASS_ON;
- }
- }
- }
-
- return ECORE_CALLBACK_PASS_ON;
-}
-
-static void
-_e_comp_wl_video_object_destroy(struct wl_resource *resource)
-{
- E_Video *video = wl_resource_get_user_data(resource);
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- VDT("Video from Client(%s):PID(%d) is being destroyed, details are: "
- "Buffer(%p), Video_Format(%c%c%c%c), "
- "Buffer_Size(%dx%d), Src Rect(%d,%d, %dx%d), Dest Rect(%d,%d, %dx%d),"
- " Transformed(%d)",
- e_client_util_name_get(video->ec) ?: "No Name" , video->ec->netwm.pid,
- video->current_fb, FOURCC_STR(video->tbmfmt),
- video->geo.input_w, video->geo.input_h, video->geo.input_r.x ,
- video->geo.input_r.y, video->geo.input_r.w, video->geo.input_r.h,
- video->geo.output_r.x ,video->geo.output_r.y, video->geo.output_r.w,
- video->geo.output_r.h, video->geo.transform);
-
- _e_video_destroy(video);
-}
-
-static void
-_e_comp_wl_video_object_cb_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(resource);
-}
-
-static void
-_e_comp_wl_video_object_cb_set_attribute(struct wl_client *client,
- struct wl_resource *resource,
- const char *name,
- int32_t value)
-{
- E_Video *video;
- int id;
-
- video = wl_resource_get_user_data(resource);
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- if(video->ec)
- VDT("Client(%s):PID(%d) RscID(%d) Attribute:%s, Value:%d",
- e_client_util_name_get(video->ec) ?: "No Name",
- video->ec->netwm.pid, wl_resource_get_id(video->surface),
- name, value);
-
- // check available property & count
- id = _e_video_get_prop_id(video, name);
- if(id < 0)
- {
- VIN("no available property");
- return;
- }
-
- if (!video->layer && video->allowed_attribute)
- {
- VIN("set layer: set_attribute");
- if (!_e_video_set_layer(video, EINA_TRUE))
- {
- VER("set layer failed");
- return;
- }
- }
-
- if (!_e_video_is_visible(video) || !video->layer)
- {
- /* if mute off, need to do it after buffer commit */
- if (!strncmp(name, "mute", TDM_NAME_LEN) && value == 0)
- {
- Tdm_Prop_Value *prop = NULL;
- const Eina_List *l = NULL;
-
- EINA_LIST_FOREACH(video->late_tdm_prop_list, l, prop)
- {
- if (!strncmp(name, prop->name, TDM_NAME_LEN))
- {
- prop->value.u32 = value;
- VDB("update property(%s) value(%d)", prop->name, value);
- return;
- }
- }
-
- prop = calloc(1, sizeof(Tdm_Prop_Value));
- if(!prop) return;
-
- prop->value.u32 = value;
- prop->id = id;
- memcpy(prop->name, name, sizeof(TDM_NAME_LEN));
- VIN("Add property(%s) value(%d)", prop->name, value);
- video->late_tdm_prop_list = eina_list_append(video->late_tdm_prop_list, prop);
- return;
- }
- }
-
- // check set video layer
- if(!video->layer)
- {
- VIN("no layer: save property value");
-
- Tdm_Prop_Value *prop = NULL;
- const Eina_List *l = NULL;
-
- EINA_LIST_FOREACH(video->tdm_prop_list, l, prop)
- {
- if (!strncmp(name, prop->name, TDM_NAME_LEN))
- {
- VDB("find prop data(%s) update value(%d -> %d)", prop->name, (unsigned int)prop->value.u32, (unsigned int)value);
- prop->value.u32 = value;
- return;
- }
- }
- EINA_LIST_FOREACH(video->late_tdm_prop_list, l, prop)
- {
- if (!strncmp(name, prop->name, TDM_NAME_LEN))
- {
- VDB("find prop data(%s) update value(%d -> %d)", prop->name, (unsigned int)prop->value.u32, (unsigned int)value);
- prop->value.u32 = value;
- return;
- }
- }
-
- prop = calloc(1, sizeof(Tdm_Prop_Value));
- if(!prop) return;
- prop->value.u32 = value;
- prop->id = id;
- memcpy(prop->name, name, sizeof(TDM_NAME_LEN));
- VIN("Add property(%s) value(%d)", prop->name, value);
- video->tdm_prop_list = eina_list_append(video->tdm_prop_list, prop);
- }
- // if set layer call property
- else
- {
- Tdm_Prop_Value prop = {.id = id, .value.u32 = value};
- VIN("set layer: call property(%s), value(%d)", name, value);
- _e_video_layer_set_property(video->layer, &prop);
- }
-}
-
-static void
-_e_comp_wl_video_object_cb_follow_topmost_visibility(struct wl_client *client,
- struct wl_resource *resource)
-{
- E_Video *video;
-
- video = wl_resource_get_user_data(resource);
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- if(!video->ec || video->follow_topmost_visibility)
- return;
-
- VIN("set follow_topmost_visibility");
-
- video->follow_topmost_visibility= EINA_TRUE;
-
-}
-
-static void
-_e_comp_wl_video_object_cb_unfollow_topmost_visibility(struct wl_client *client,
- struct wl_resource *resource)
-{
- E_Video *video;
-
- video = wl_resource_get_user_data(resource);
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- if(!video->ec || !video->follow_topmost_visibility)
- return;
-
- VIN("set unfollow_topmost_visibility");
-
- video->follow_topmost_visibility= EINA_FALSE;
-
-}
-
-static void
-_e_comp_wl_video_object_cb_allowed_attribute(struct wl_client *client,
- struct wl_resource *resource)
-{
- E_Video *video;
-
- video = wl_resource_get_user_data(resource);
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- if(!video->ec || video->allowed_attribute)
- return;
-
- VIN("set allowed_attribute");
-
- video->allowed_attribute = EINA_TRUE;
-
-}
-
-static void
-_e_comp_wl_video_object_cb_disallowed_attribute(struct wl_client *client,
- struct wl_resource *resource)
-{
- E_Video *video;
-
- video = wl_resource_get_user_data(resource);
- EINA_SAFETY_ON_NULL_RETURN(video);
-
- if(!video->ec || !video->allowed_attribute)
- return;
-
- VIN("set disallowed_attribute");
-
- video->allowed_attribute = EINA_FALSE;
-
-}
-
-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_set_attribute,
- _e_comp_wl_video_object_cb_follow_topmost_visibility,
- _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,
-};
-
-static void
-_e_comp_wl_video_cb_get_object(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface)
-{
- E_Video *video;
- int version = wl_resource_get_version(resource);
- struct wl_resource *res;
-
- res = wl_resource_create(client, &tizen_video_object_interface, version, id);
- if (res == NULL)
- {
- wl_client_post_no_memory(client);
- return;
- }
-
- if (!(video = _e_video_create(res, surface)))
- {
- wl_resource_destroy(res);
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(res, &_e_comp_wl_video_object_interface,
- video, _e_comp_wl_video_object_destroy);
-}
-
-static void
-_e_comp_wl_video_cb_get_viewport(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface)
-{
- E_Client *ec;
-
- if (!(ec = wl_resource_get_user_data(surface))) return;
- if (!ec->comp_data) return;
-
- if (ec->comp_data && ec->comp_data->scaler.viewport)
- {
- wl_resource_post_error(resource,
- TIZEN_VIDEO_ERROR_VIEWPORT_EXISTS,
- "a viewport for that subsurface already exists");
- return;
- }
-
- if (!e_comp_wl_viewport_create(resource, id, surface))
- {
- ERR("Failed to create viewport for wl_surface@%d",
- wl_resource_get_id(surface));
- wl_client_post_no_memory(client);
- return;
- }
-}
-
-static void
-_e_comp_wl_video_cb_destroy(struct wl_client *client, struct wl_resource *resource)
-{
- wl_resource_destroy(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,
-};
-
-static void
-_e_comp_wl_video_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
-{
- struct wl_resource *res;
- const uint32_t *formats = NULL;
- int i, count = 0;
- Eina_List *pp_format_list = NULL;
- Eina_List *l = NULL;
- uint32_t *pp_format;
-
- if (!(res = wl_resource_create(client, &tizen_video_interface, version, id)))
- {
- ERR("Could not create tizen_video_interface resource: %m");
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(res, &_e_comp_wl_video_interface, NULL, NULL);
-
- /* 1st, use pp information. */
- if (e_comp_screen_pp_support())
- pp_format_list = e_comp_screen_pp_available_formats_get();
-
- if (pp_format_list)
- {
- EINA_LIST_FOREACH(pp_format_list, l, pp_format)
- tizen_video_send_format(res, *pp_format);
- }
- else
- {
- _e_video_get_available_formats(&formats, &count);
- for (i = 0; i < count; i++)
- tizen_video_send_format(res, formats[i]);
- }
-}
-
-static Eina_List *video_hdlrs;
-
-static void
-_e_comp_wl_vbuf_print(void *data, const char *log_path)
-{
- e_comp_wl_video_buffer_list_print(log_path);
-}
-
-static void
-_e_comp_wl_video_to_primary(void *data, const char *log_path)
-{
- video_to_primary = !video_to_primary;
-}
-
-static void
-_e_comp_wl_video_punch(void *data, const char *log_path)
-{
- video_punch = !video_punch;
-}
-
-EINTERN int
-e_comp_wl_video_init(void)
-{
- e_comp->wl_comp_data->available_hw_accel.underlay = EINA_TRUE;
- DBG("enable HW underlay");
-
- e_comp->wl_comp_data->available_hw_accel.scaler = EINA_TRUE;
- DBG("enable HW scaler");
-
- if (!e_comp_wl) return 0;
- if (!e_comp_wl->wl.disp) return 0;
- if (e_comp->wl_comp_data->video.global) return 1;
-
- e_info_server_hook_set("vbuf", _e_comp_wl_vbuf_print, NULL);
- e_info_server_hook_set("video-to-primary", _e_comp_wl_video_to_primary, NULL);
- e_info_server_hook_set("video-punch", _e_comp_wl_video_punch, NULL);
-
- _video_detail_log_dom = eina_log_domain_register("e-comp-wl-video", EINA_COLOR_BLUE);
- if (_video_detail_log_dom < 0)
- {
- ERR("Failed eina_log_domain_register()..!\n");
- return 0;
- }
-
- /* 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);
-
- if (!e_comp->wl_comp_data->video.global)
- {
- ERR("Could not add tizen_video to wayland globals");
- return 0;
- }
-
- E_LIST_HANDLER_APPEND(video_hdlrs, E_EVENT_CLIENT_BUFFER_CHANGE,
- _e_video_cb_ec_buffer_change, NULL);
- E_LIST_HANDLER_APPEND(video_hdlrs, E_EVENT_CLIENT_REMOVE,
- _e_video_cb_ec_remove, NULL);
- E_LIST_HANDLER_APPEND(video_hdlrs, E_EVENT_CLIENT_SHOW,
- _e_video_cb_ec_client_show, NULL);
- E_LIST_HANDLER_APPEND(video_hdlrs, E_EVENT_REMOTE_SURFACE_PROVIDER_VISIBILITY_CHANGE,
- _e_video_cb_ec_visibility_change, NULL);
- E_LIST_HANDLER_APPEND(video_hdlrs, E_EVENT_CLIENT_VISIBILITY_CHANGE,
- _e_video_cb_topmost_ec_visibility_change, NULL);
-
- return 1;
-}
-
-EINTERN void
-e_comp_wl_video_shutdown(void)
-{
- e_comp->wl_comp_data->available_hw_accel.underlay = EINA_FALSE;
- e_comp->wl_comp_data->available_hw_accel.scaler = EINA_FALSE;
-
- E_FREE_FUNC(e_comp->wl_comp_data->video.global, wl_global_destroy);
- E_FREE_LIST(video_hdlrs, ecore_event_handler_del);
-
- e_info_server_hook_set("vbuf", NULL, NULL);
- e_info_server_hook_set("video-dst-change", NULL, NULL);
- e_info_server_hook_set("video-to-primary", NULL, NULL);
- e_info_server_hook_set("video-punch", NULL, NULL);
-
- eina_log_domain_unregister(_video_detail_log_dom);
- _video_detail_log_dom = -1;
-}
-
-static tdm_layer *
-_e_video_tdm_video_layer_get(tdm_output *output)
-{
- int i, count = 0;
-#ifdef CHECKING_PRIMARY_ZPOS
- int primary_idx = 0, primary_zpos = 0;
- tdm_layer *primary_layer;
-#endif
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
-
- tdm_output_get_layer_count(output, &count);
- for (i = 0; i < count; i++)
- {
- tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
- tdm_layer_capability capabilities = 0;
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
-
- tdm_layer_get_capabilities(layer, &capabilities);
- if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
- return layer;
- }
-
-#ifdef CHECKING_PRIMARY_ZPOS
- tdm_output_get_primary_index(output, &primary_idx);
- primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
- EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
- tdm_layer_get_zpos(primary_layer, &primary_zpos);
-#endif
-
- for (i = 0; i < count; i++)
- {
- tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
- tdm_layer_capability capabilities = 0;
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
-
- tdm_layer_get_capabilities(layer, &capabilities);
- if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
- {
-#ifdef CHECKING_PRIMARY_ZPOS
- int zpos = 0;
- tdm_layer_get_zpos(layer, &zpos);
- if (zpos >= primary_zpos) continue;
-#endif
- return layer;
- }
- }
-
- return NULL;
-}
-
-static tdm_layer *
-_e_video_tdm_available_video_layer_get(tdm_output *output)
-{
- Eina_Bool has_video_layer = EINA_FALSE;
- int i, count = 0;
-#ifdef CHECKING_PRIMARY_ZPOS
- int primary_idx = 0, primary_zpos = 0;
- tdm_layer *primary_layer;
-#endif
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
-
- /* check video layers first */
- tdm_output_get_layer_count(output, &count);
- for (i = 0; i < count; i++)
- {
- tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
- tdm_layer_capability capabilities = 0;
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
-
- tdm_layer_get_capabilities(layer, &capabilities);
- if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
- {
- has_video_layer = EINA_TRUE;
- if (!_e_video_tdm_get_layer_usable(layer)) continue;
- return layer;
- }
- }
-
- /* if a output has video layers, it means that there is no available video layer for video */
- if (has_video_layer)
- return NULL;
-
- /* check graphic layers second */
-#ifdef CHECKING_PRIMARY_ZPOS
- tdm_output_get_primary_index(output, &primary_idx);
- primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
- EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
- tdm_layer_get_zpos(primary_layer, &primary_zpos);
-#endif
-
- for (i = 0; i < count; i++)
- {
- tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
- tdm_layer_capability capabilities = 0;
- EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
-
- tdm_layer_get_capabilities(layer, &capabilities);
- if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
- {
-#ifdef CHECKING_PRIMARY_ZPOS
- int zpos = 0;
- tdm_layer_get_zpos(layer, &zpos);
- if (zpos >= primary_zpos) continue;
-#endif
- if (!_e_video_tdm_get_layer_usable(layer)) continue;
- return layer;
- }
- }
-
- return NULL;
-}
-
-static void
-_e_video_tdm_set_layer_usable(tdm_layer *layer, Eina_Bool usable)
-{
- if (usable)
- video_layers = eina_list_remove(video_layers, layer);
- else
- {
- tdm_layer *used_layer;
- Eina_List *l = NULL;
- EINA_LIST_FOREACH(video_layers, l, used_layer)
- if (used_layer == layer) return;
- video_layers = eina_list_append(video_layers, layer);
- }
-}
-
-static Eina_Bool
-_e_video_tdm_get_layer_usable(tdm_layer *layer)
-{
- tdm_layer *used_layer;
- Eina_List *l = NULL;
- EINA_LIST_FOREACH(video_layers, l, used_layer)
- if (used_layer == layer)
- return EINA_FALSE;
- return EINA_TRUE;
-}
+++ /dev/null
-#ifdef E_TYPEDEFS
-
-#else
-#ifndef E_COMP_WL_VIDEO_H
-#define E_COMP_WL_VIDEO_H
-
-#define E_COMP_WL
-
-typedef struct _E_Video E_Video;
-typedef struct _E_Video_Layer E_Video_Layer;
-typedef struct _E_Video_Info_Layer E_Video_Info_Layer;
-
-EINTERN int e_comp_wl_video_init(void);
-EINTERN void e_comp_wl_video_shutdown(void);
-
-EINTERN void e_comp_wl_video_hwc_window_commit_data_release(E_Hwc_Window *hwc_window, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
-EINTERN tbm_surface_h e_comp_wl_video_hwc_widow_surface_get(E_Hwc_Window *hwc_window);
-EINTERN Eina_Bool e_comp_wl_video_hwc_window_info_get(E_Hwc_Window *hwc_window, tdm_hwc_window_info *hwc_win_info);
-
-#define C(b,m) (((b) >> (m)) & 0xFF)
-#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24)
-#define IS_RGB(f) ((f) == TBM_FORMAT_XRGB8888 || (f) == TBM_FORMAT_ARGB8888)
-#define ROUNDUP(s,c) (((s) + (c-1)) & ~(c-1))
-
-#endif
-#endif
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "e.h"
-#include <wayland-tbm-server.h>
-#include <sys/mman.h>
-#include <pixman.h>
-#include <tdm_helper.h>
-
-//#define DEBUG_LIFECYCLE
-
-#define BER(fmt,arg...) ERR("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
-#define BWR(fmt,arg...) WRN("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
-#define BIN(fmt,arg...) INF("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
-#define BDB(fmt,arg...) DBG("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
-
-#define VBUF_RETURN_IF_FAIL(cond) \
- {if (!(cond)) { BER("'%s' failed", #cond); return; }}
-#define VBUF_RETURN_VAL_IF_FAIL(cond, val) \
- {if (!(cond)) { BER("'%s' failed", #cond); return val; }}
-
-#ifdef DEBUG_LIFECYCLE
-#undef BDB
-#define BDB BIN
-#endif
-
-typedef struct _VBufFreeFuncInfo
-{
- VBuf_Free_Func func;
- void *data;
-} VBufFreeFuncInfo;
-
-static void _e_comp_wl_video_buffer_cb_destroy(struct wl_listener *listener, void *data);
-static void _e_comp_wl_video_buffer_free(E_Comp_Wl_Video_Buf *vbuf);
-#define e_comp_wl_video_buffer_free(b) _e_comp_wl_video_buffer_free(b)
-
-static Eina_List *vbuf_lists;
-
-static E_Comp_Wl_Video_Buf*
-_find_vbuf(uint stamp)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l;
-
- if (!vbuf_lists)
- return NULL;
-
- EINA_LIST_FOREACH(vbuf_lists, l, vbuf)
- {
- if (vbuf->stamp == stamp)
- return vbuf;
- }
-
- return NULL;
-}
-
-static Eina_Bool
-_e_comp_wl_video_buffer_access_data_begin(E_Comp_Wl_Video_Buf *vbuf)
-{
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, EINA_FALSE);
-
- vbuf->ptrs[0] = vbuf->ptrs[1] = vbuf->ptrs[2] = NULL;
-
- if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_SHM)
- {
- struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(vbuf->resource);
- EINA_SAFETY_ON_NULL_RETURN_VAL(shm_buffer, EINA_FALSE);
- vbuf->ptrs[0] = wl_shm_buffer_get_data(shm_buffer);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf->ptrs[0], EINA_FALSE);
- return EINA_TRUE;
- }
- else if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_TBM)
- {
- int i, j;
- tbm_bo bos[4] = {0,};
-
- for (i = 0; i < 3; i++)
- {
- tbm_bo_handle bo_handles;
-
- bos[i] = tbm_surface_internal_get_bo(vbuf->tbm_surface, i);
- if (!bos[i]) continue;
-
- bo_handles = tbm_bo_map(bos[i], TBM_DEVICE_CPU, TBM_OPTION_READ);
- if (!bo_handles.ptr)
- {
- for (j = 0; j < i; j++)
- tbm_bo_unmap(bos[j]);
- return EINA_FALSE;
- }
-
- vbuf->ptrs[i] = bo_handles.ptr;
- }
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf->ptrs[0], EINA_FALSE);
-
- switch(vbuf->tbmfmt)
- {
- case TBM_FORMAT_YVU420:
- case TBM_FORMAT_YUV420:
- if (!vbuf->ptrs[1])
- vbuf->ptrs[1] = vbuf->ptrs[0];
- if (!vbuf->ptrs[2])
- vbuf->ptrs[2] = vbuf->ptrs[1];
- break;
- case TBM_FORMAT_NV12:
- case TBM_FORMAT_NV21:
- if (!vbuf->ptrs[1])
- vbuf->ptrs[1] = vbuf->ptrs[0];
- break;
- default:
- break;
- }
-
- return EINA_TRUE;
- }
-
- return EINA_FALSE;
-}
-
-static void
-_e_comp_wl_video_buffer_access_data_end(E_Comp_Wl_Video_Buf *vbuf)
-{
- EINA_SAFETY_ON_NULL_RETURN(vbuf);
-
- if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_SHM)
- {
- vbuf->ptrs[0] = NULL;
- }
- else if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_TBM)
- {
- int i;
- tbm_bo bos[4] = {0,};
-
- for (i = 0; i < 3; i++)
- {
- bos[i] = tbm_surface_internal_get_bo(vbuf->tbm_surface, i);
- if (!bos[i]) continue;
-
- tbm_bo_unmap(bos[i]);
- vbuf->ptrs[i] = NULL;
- }
- }
-}
-
-static E_Comp_Wl_Video_Buf*
-_e_comp_wl_video_buffer_create_res(struct wl_resource *resource)
-{
- E_Comp_Wl_Video_Buf *vbuf = NULL;
- struct wl_shm_buffer *shm_buffer;
- tbm_surface_h tbm_surface;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(resource, NULL);
-
- vbuf = calloc(1, sizeof(E_Comp_Wl_Video_Buf));
- EINA_SAFETY_ON_FALSE_GOTO(vbuf != NULL, create_fail);
-
- vbuf->ref_cnt = 1;
- vbuf->stamp = e_comp_wl_video_buffer_get_mills();
- while (_find_vbuf(vbuf->stamp))
- vbuf->stamp++;
-
- vbuf->resource = resource;
-
- if ((shm_buffer = wl_shm_buffer_get(resource)))
- {
- uint32_t tbmfmt = wl_shm_buffer_get_format(shm_buffer);
-
- vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_SHM;
-
- if (tbmfmt == WL_SHM_FORMAT_ARGB8888)
- vbuf->tbmfmt = TBM_FORMAT_ARGB8888;
- else if (tbmfmt == WL_SHM_FORMAT_XRGB8888)
- vbuf->tbmfmt = TBM_FORMAT_XRGB8888;
- else
- vbuf->tbmfmt = tbmfmt;
-
- vbuf->width = wl_shm_buffer_get_width(shm_buffer);
- vbuf->height = wl_shm_buffer_get_height(shm_buffer);
- vbuf->pitches[0] = wl_shm_buffer_get_stride(shm_buffer);
-
- vbuf->width_from_pitch = vbuf->width;
- vbuf->height_from_size = vbuf->height;;
- }
- else if ((tbm_surface = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, resource)))
- {
- int i;
-
- vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_TBM;
- vbuf->tbm_surface = tbm_surface;
- tbm_surface_internal_ref(tbm_surface);
-
- vbuf->tbmfmt = tbm_surface_get_format(tbm_surface);
- vbuf->width = tbm_surface_get_width(tbm_surface);
- vbuf->height = tbm_surface_get_height(tbm_surface);
-
- /* NOTE Some format such a NVxx and a YUVxxx can have multiple handles */
- for (i = 0; i < 3; i++)
- {
- uint32_t size = 0, offset = 0, pitch = 0;
- tbm_bo bo;
-
- bo = tbm_surface_internal_get_bo(tbm_surface, i);
- if (bo)
- {
- vbuf->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
- EINA_SAFETY_ON_FALSE_GOTO(vbuf->handles[i] > 0, create_fail);
-
- vbuf->names[i] = tbm_bo_export(bo);
- EINA_SAFETY_ON_FALSE_GOTO(vbuf->names[i] > 0, create_fail);
- }
-
- tbm_surface_internal_get_plane_data(tbm_surface, i, &size, &offset, &pitch);
- vbuf->pitches[i] = pitch;
- vbuf->offsets[i] = offset;
- }
-
- tdm_helper_get_buffer_full_size(tbm_surface, &vbuf->width_from_pitch, &vbuf->height_from_size);
- }
- else
- {
- ERR("unknown buffer resource");
- goto create_fail;
- }
-
- vbuf_lists = eina_list_append(vbuf_lists, vbuf);
-
- BDB("type(%d) %dx%d(%dx%d), %c%c%c%c, name(%d,%d,%d) hnd(%d,%d,%d), pitch(%d,%d,%d), offset(%d,%d,%d)",
- vbuf->type, vbuf->width_from_pitch, vbuf->height_from_size,
- vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
- vbuf->names[0], vbuf->names[1], vbuf->names[2],
- vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
- vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
- vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2]);
-
- return vbuf;
-
-create_fail:
- _e_comp_wl_video_buffer_free(vbuf);
-
- return NULL;
-}
-
-EINTERN E_Comp_Wl_Video_Buf*
-e_comp_wl_video_buffer_create(struct wl_resource *resource)
-{
- E_Comp_Wl_Video_Buf *vbuf = _e_comp_wl_video_buffer_create_res(resource);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
-
- vbuf->destroy_listener.notify = _e_comp_wl_video_buffer_cb_destroy;
- wl_resource_add_destroy_listener(resource, &vbuf->destroy_listener);
-
- return vbuf;
-}
-
-EINTERN E_Comp_Wl_Video_Buf*
-e_comp_wl_video_buffer_create_comp(E_Comp_Wl_Buffer *comp_buffer)
-{
- E_Comp_Wl_Video_Buf *vbuf;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(comp_buffer, NULL);
-
- vbuf = _e_comp_wl_video_buffer_create_res(comp_buffer->resource);
- EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
-
- vbuf->comp_buffer = comp_buffer;
-
- vbuf->destroy_listener.notify = _e_comp_wl_video_buffer_cb_destroy;
- wl_resource_add_destroy_listener(comp_buffer->resource, &vbuf->destroy_listener);
-
- return vbuf;
-}
-
-EINTERN E_Comp_Wl_Video_Buf*
-e_comp_wl_video_buffer_create_tbm(tbm_surface_h tbm_surface)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- int i;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, NULL);
-
- vbuf = calloc(1, sizeof(E_Comp_Wl_Video_Buf));
- EINA_SAFETY_ON_FALSE_GOTO(vbuf != NULL, create_fail);
-
- vbuf->ref_cnt = 1;
- vbuf->stamp = e_comp_wl_video_buffer_get_mills();
- while (_find_vbuf(vbuf->stamp))
- vbuf->stamp++;
-
- vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_TBM;
- vbuf->tbm_surface = tbm_surface;
- tbm_surface_internal_ref(tbm_surface);
-
- vbuf->tbmfmt = tbm_surface_get_format(tbm_surface);
- vbuf->width = tbm_surface_get_width(tbm_surface);
- vbuf->height = tbm_surface_get_height(tbm_surface);
-
- for (i = 0; i < 3; i++)
- {
- uint32_t size = 0, offset = 0, pitch = 0;
- tbm_bo bo;
-
- bo = tbm_surface_internal_get_bo(tbm_surface, i);
- if (bo)
- {
- vbuf->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
- EINA_SAFETY_ON_FALSE_GOTO(vbuf->handles[i] > 0, create_fail);
-
- vbuf->names[i] = tbm_bo_export(bo);
- EINA_SAFETY_ON_FALSE_GOTO(vbuf->names[i] > 0, create_fail);
- }
-
- tbm_surface_internal_get_plane_data(tbm_surface, i, &size, &offset, &pitch);
- vbuf->pitches[i] = pitch;
- vbuf->offsets[i] = offset;
- }
-
- tdm_helper_get_buffer_full_size(tbm_surface, &vbuf->width_from_pitch, &vbuf->height_from_size);
-
- vbuf_lists = eina_list_append(vbuf_lists, vbuf);
-
- BDB("type(%d) %dx%d(%dx%d), %c%c%c%c, name(%d,%d,%d) hnd(%d,%d,%d), pitch(%d,%d,%d), offset(%d,%d,%d)",
- vbuf->type, vbuf->width_from_pitch, vbuf->height_from_size,
- vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
- vbuf->names[0], vbuf->names[1], vbuf->names[2],
- vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
- vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
- vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2]);
-
- return vbuf;
-
-create_fail:
- _e_comp_wl_video_buffer_free(vbuf);
-
- return NULL;
-}
-
-EINTERN E_Comp_Wl_Video_Buf*
-e_comp_wl_video_buffer_alloc(int width, int height, tbm_format tbmfmt, Eina_Bool scanout)
-{
- E_Comp_Wl_Video_Buf *vbuf = NULL;
- tbm_surface_h tbm_surface = NULL;
- int i;
-
- EINA_SAFETY_ON_FALSE_RETURN_VAL(width > 0, NULL);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(height > 0, NULL);
-
- vbuf = calloc(1, sizeof(E_Comp_Wl_Video_Buf));
- EINA_SAFETY_ON_FALSE_GOTO(vbuf != NULL, alloc_fail);
-
- vbuf->ref_cnt = 1;
- vbuf->stamp = e_comp_wl_video_buffer_get_mills();
- while (_find_vbuf(vbuf->stamp))
- vbuf->stamp++;
-
- if (scanout)
- tbm_surface = tbm_surface_internal_create_with_flags(width, height, tbmfmt, TBM_BO_SCANOUT);
- else
- tbm_surface = tbm_surface_internal_create_with_flags(width, height, tbmfmt, TBM_BO_DEFAULT);
- EINA_SAFETY_ON_NULL_GOTO(tbm_surface, alloc_fail);
-
- vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_TBM;
- vbuf->tbm_surface = tbm_surface;
- tbm_surface_internal_ref(tbm_surface);
-
- vbuf->tbmfmt = tbmfmt;
- vbuf->width = width;
- vbuf->height = height;
-
- for (i = 0; i < 3; i++)
- {
- uint32_t size = 0, offset = 0, pitch = 0;
- tbm_bo bo;
-
- bo = tbm_surface_internal_get_bo(tbm_surface, i);
- if (bo)
- {
- vbuf->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
- EINA_SAFETY_ON_FALSE_GOTO(vbuf->handles[i] > 0, alloc_fail);
-
- vbuf->names[i] = tbm_bo_export(bo);
- EINA_SAFETY_ON_FALSE_GOTO(vbuf->names[i] > 0, alloc_fail);
- }
-
- tbm_surface_internal_get_plane_data(tbm_surface, i, &size, &offset, &pitch);
- vbuf->pitches[i] = pitch;
- vbuf->offsets[i] = offset;
- }
-
- tdm_helper_get_buffer_full_size(tbm_surface, &vbuf->width_from_pitch, &vbuf->height_from_size);
-
- tbm_surface_internal_unref(tbm_surface);
-
- vbuf_lists = eina_list_append(vbuf_lists, vbuf);
-
- BDB("type(%d) %dx%d(%dx%d) %c%c%c%c nm(%d,%d,%d) hnd(%d,%d,%d) pitch(%d,%d,%d) offset(%d,%d,%d)",
- vbuf->type, vbuf->width_from_pitch, vbuf->height_from_size,
- vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
- vbuf->names[0], vbuf->names[1], vbuf->names[2],
- vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
- vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
- vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2]);
-
- return vbuf;
-
-alloc_fail:
- if (tbm_surface)
- tbm_surface_internal_unref(tbm_surface);
- _e_comp_wl_video_buffer_free(vbuf);
- return NULL;
-}
-
-EINTERN E_Comp_Wl_Video_Buf*
-e_comp_wl_video_buffer_ref(E_Comp_Wl_Video_Buf *vbuf)
-{
- if (!vbuf)
- return NULL;
-
- EINA_SAFETY_ON_FALSE_RETURN_VAL(VBUF_IS_VALID(vbuf), NULL);
-
- vbuf->ref_cnt++;
- BDB("count(%d) ref", vbuf->ref_cnt);
-
- return vbuf;
-}
-
-EINTERN void
-e_comp_wl_video_buffer_unref(E_Comp_Wl_Video_Buf *vbuf)
-{
- if (!vbuf)
- return;
-
- VBUF_RETURN_IF_FAIL(e_comp_wl_video_buffer_valid(vbuf));
-
- vbuf->ref_cnt--;
- BDB("count(%d) unref", vbuf->ref_cnt);
-
- if (!vbuf->buffer_destroying && vbuf->ref_cnt == 0)
- _e_comp_wl_video_buffer_free(vbuf);
-}
-
-static void
-_e_comp_wl_video_buffer_free(E_Comp_Wl_Video_Buf *vbuf)
-{
- VBufFreeFuncInfo *info;
- Eina_List *l, *ll;
-
- if (!vbuf)
- return;
-
- VBUF_RETURN_IF_FAIL(e_comp_wl_video_buffer_valid(vbuf));
-
- BDB("vbuf(%p) tbm_surface(%p) freed", vbuf, vbuf->tbm_surface);
-
- vbuf->buffer_destroying = EINA_TRUE;
-
- if (vbuf->destroy_listener.notify)
- {
- wl_list_remove(&vbuf->destroy_listener.link);
- vbuf->destroy_listener.notify = NULL;
- }
-
- EINA_LIST_FOREACH_SAFE(vbuf->free_funcs, l, ll, info)
- {
- /* call before tmb_bo_unref */
- vbuf->free_funcs = eina_list_remove_list(vbuf->free_funcs, l);
- if (info->func)
- info->func(vbuf, info->data);
- free(info);
- }
-
-#if 0
- /* DO not check ref_count here. Even if ref_count is not 0, vbuf can be
- * be destroyed by wl_buffer_destroy forcely. video or screenmirror should add
- * the vbuf free function and handle the destroying vbuf situation.
- */
- if (!vbuf->buffer_destroying)
- VBUF_RETURN_IF_FAIL(vbuf->ref_cnt == 0);
-#endif
-
- /* make sure all operation is done */
- VBUF_RETURN_IF_FAIL(vbuf->in_use == EINA_FALSE);
-
- if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_TBM && vbuf->tbm_surface)
- {
- tbm_surface_internal_unref(vbuf->tbm_surface);
- vbuf->tbm_surface = NULL;
- }
-
- vbuf_lists = eina_list_remove(vbuf_lists, vbuf);
-
- vbuf->stamp = 0;
-
- free(vbuf);
-}
-
-static void
-_e_comp_wl_video_buffer_cb_destroy(struct wl_listener *listener, void *data)
-{
- E_Comp_Wl_Video_Buf *vbuf = container_of(listener, E_Comp_Wl_Video_Buf, destroy_listener);
-
- if (!vbuf) return;
-
- vbuf->comp_buffer = NULL;
-
- if (vbuf->buffer_destroying == EINA_FALSE)
- {
- vbuf->destroy_listener.notify = NULL;
- _e_comp_wl_video_buffer_free(vbuf);
- }
-}
-
-EINTERN void
-e_comp_wl_video_buffer_clear(E_Comp_Wl_Video_Buf *vbuf)
-{
- EINA_SAFETY_ON_NULL_RETURN(vbuf);
-
- if (!_e_comp_wl_video_buffer_access_data_begin(vbuf))
- {
- BER("can't access ptr");
- return;
- }
-
- switch(vbuf->tbmfmt)
- {
- case TBM_FORMAT_ARGB8888:
- case TBM_FORMAT_XRGB8888:
- memset(vbuf->ptrs[0], 0, vbuf->pitches[0] * vbuf->height);
- break;
- case TBM_FORMAT_YVU420:
- case TBM_FORMAT_YUV420:
- memset((char*)vbuf->ptrs[0] + vbuf->offsets[0], 0x10, vbuf->pitches[0] * vbuf->height);
- memset((char*)vbuf->ptrs[1] + vbuf->offsets[1], 0x80, vbuf->pitches[1] * (vbuf->height >> 1));
- memset((char*)vbuf->ptrs[2] + vbuf->offsets[2], 0x80, vbuf->pitches[2] * (vbuf->height >> 1));
- break;
- case TBM_FORMAT_NV12:
- case TBM_FORMAT_NV21:
- memset((char*)vbuf->ptrs[0] + vbuf->offsets[0], 0x10, vbuf->pitches[0] * vbuf->height);
- memset((char*)vbuf->ptrs[1] + vbuf->offsets[1], 0x80, vbuf->pitches[1] * (vbuf->height >> 1));
- break;
- case TBM_FORMAT_YUYV:
- {
- int *ibuf = (int*)vbuf->ptrs[0];
- int i, size = vbuf->pitches[0] * vbuf->height / 4;
-
- for (i = 0 ; i < size ; i++)
- ibuf[i] = 0x10801080;
- }
- break;
- case TBM_FORMAT_UYVY:
- {
- int *ibuf = (int*)vbuf->ptrs[0];
- int i, size = vbuf->pitches[0] * vbuf->height / 4;
-
- for (i = 0 ; i < size ; i++)
- ibuf[i] = 0x80108010; /* YUYV -> 0xVYUY */
- }
- break;
- default:
- BWR("can't clear %c%c%c%c buffer", FOURCC_STR(vbuf->tbmfmt));
- break;
- }
-
- _e_comp_wl_video_buffer_access_data_end(vbuf);
-}
-
-EINTERN Eina_Bool
-e_comp_wl_video_buffer_valid(E_Comp_Wl_Video_Buf *vbuf)
-{
- E_Comp_Wl_Video_Buf *temp;
- Eina_List *l;
-
- VBUF_RETURN_VAL_IF_FAIL(vbuf != NULL, EINA_FALSE);
- VBUF_RETURN_VAL_IF_FAIL(vbuf->stamp != 0, EINA_FALSE);
-
- EINA_LIST_FOREACH(vbuf_lists, l, temp)
- {
- if (temp->stamp == vbuf->stamp)
- return EINA_TRUE;
- }
-
- BDB("vbuf(%p) invalid", vbuf);
-
- return EINA_FALSE;
-}
-
-static VBufFreeFuncInfo*
-_e_comp_wl_video_buffer_free_func_find(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data)
-{
- VBufFreeFuncInfo *info;
- Eina_List *l;
-
- EINA_LIST_FOREACH(vbuf->free_funcs, l, info)
- {
- if (info->func == func && info->data == data)
- return info;
- }
-
- return NULL;
-}
-
-EINTERN void
-e_comp_wl_video_buffer_free_func_add(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data)
-{
- VBufFreeFuncInfo *info;
-
- EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(vbuf));
- EINA_SAFETY_ON_NULL_RETURN(func);
-
- info = _e_comp_wl_video_buffer_free_func_find(vbuf, func, data);
- if (info)
- return;
-
- info = calloc(1, sizeof(VBufFreeFuncInfo));
- EINA_SAFETY_ON_NULL_RETURN(info);
-
- info->func = func;
- info->data = data;
-
- vbuf->free_funcs = eina_list_append(vbuf->free_funcs, info);
-}
-
-EINTERN void
-e_comp_wl_video_buffer_free_func_del(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data)
-{
- VBufFreeFuncInfo *info;
-
- EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(vbuf));
- EINA_SAFETY_ON_NULL_RETURN(func);
-
- info = _e_comp_wl_video_buffer_free_func_find(vbuf, func, data);
- if (!info)
- return;
-
- vbuf->free_funcs = eina_list_remove(vbuf->free_funcs, info);
-
- free(info);
-}
-
-static pixman_format_code_t
-_e_comp_wl_video_buffer_pixman_format_get(E_Comp_Wl_Video_Buf *vbuf)
-{
- switch(vbuf->tbmfmt)
- {
- case TBM_FORMAT_ARGB8888: return PIXMAN_a8r8g8b8;
- case TBM_FORMAT_XRGB8888: return PIXMAN_x8r8g8b8;
- default: return 0;
- }
- return 0;
-}
-
-EINTERN void
-e_comp_wl_video_buffer_convert(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf,
- int sx, int sy, int sw, int sh,
- int dx, int dy, int dw, int dh,
- Eina_Bool over, int rotate, int hflip, int vflip)
-{
- pixman_image_t *src_img = NULL, *dst_img = NULL;
- pixman_format_code_t src_format, dst_format;
- double scale_x, scale_y;
- int rotate_step;
- pixman_transform_t t;
- struct pixman_f_transform ft;
- pixman_op_t op;
- int src_stride, dst_stride;
- int buf_width;
-
- EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(srcbuf));
- EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(dstbuf));
-
- if (!_e_comp_wl_video_buffer_access_data_begin(srcbuf))
- return;
- if (!_e_comp_wl_video_buffer_access_data_begin(dstbuf))
- {
- _e_comp_wl_video_buffer_access_data_end(srcbuf);
- return;
- }
-
- /* not handle buffers which have 2 more gem handles */
- EINA_SAFETY_ON_NULL_GOTO(srcbuf->ptrs[0], cant_convert);
- EINA_SAFETY_ON_NULL_GOTO(dstbuf->ptrs[0], cant_convert);
- EINA_SAFETY_ON_FALSE_RETURN(!srcbuf->ptrs[1]);
- EINA_SAFETY_ON_FALSE_RETURN(!dstbuf->ptrs[1]);
-
- src_format = _e_comp_wl_video_buffer_pixman_format_get(srcbuf);
- EINA_SAFETY_ON_FALSE_GOTO(src_format > 0, cant_convert);
- dst_format = _e_comp_wl_video_buffer_pixman_format_get(dstbuf);
- EINA_SAFETY_ON_FALSE_GOTO(dst_format > 0, cant_convert);
-
- buf_width = IS_RGB(srcbuf->tbmfmt)?(srcbuf->pitches[0]/4):srcbuf->pitches[0];
- src_stride = IS_RGB(srcbuf->tbmfmt)?(srcbuf->pitches[0]):buf_width * (PIXMAN_FORMAT_BPP(src_format) / 8);
- src_img = pixman_image_create_bits(src_format, buf_width, srcbuf->height,
- (uint32_t*)srcbuf->ptrs[0], src_stride);
- EINA_SAFETY_ON_NULL_GOTO(src_img, cant_convert);
-
- buf_width = IS_RGB(dstbuf->tbmfmt)?(dstbuf->pitches[0]/4):dstbuf->pitches[0];
- dst_stride = IS_RGB(srcbuf->tbmfmt)?(dstbuf->pitches[0]):buf_width * (PIXMAN_FORMAT_BPP(dst_format) / 8);
- dst_img = pixman_image_create_bits(dst_format, buf_width, dstbuf->height,
- (uint32_t*)dstbuf->ptrs[0], dst_stride);
- EINA_SAFETY_ON_NULL_GOTO(dst_img, cant_convert);
-
- pixman_f_transform_init_identity(&ft);
-
- if (hflip)
- {
- pixman_f_transform_scale(&ft, NULL, -1, 1);
- pixman_f_transform_translate(&ft, NULL, dw, 0);
- }
-
- if (vflip)
- {
- pixman_f_transform_scale(&ft, NULL, 1, -1);
- pixman_f_transform_translate(&ft, NULL, 0, dh);
- }
-
- rotate_step = (rotate + 360) / 90 % 4;
- if (rotate_step > 0)
- {
- int c, s, tx = 0, ty = 0;
- switch (rotate_step)
- {
- case 1:
- c = 0, s = -1, tx = -dw;
- break;
- case 2:
- c = -1, s = 0, tx = -dw, ty = -dh;
- break;
- case 3:
- c = 0, s = 1, ty = -dh;
- break;
- }
- pixman_f_transform_translate(&ft, NULL, tx, ty);
- pixman_f_transform_rotate(&ft, NULL, c, s);
- }
-
- if (rotate_step % 2 == 0)
- {
- scale_x = (double)sw / dw;
- scale_y = (double)sh / dh;
- }
- else
- {
- scale_x = (double)sw / dh;
- scale_y = (double)sh / dw;
- }
-
- pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
- pixman_f_transform_translate(&ft, NULL, sx, sy);
- pixman_transform_from_pixman_f_transform(&t, &ft);
- pixman_image_set_transform(src_img, &t);
-
- if (!over) op = PIXMAN_OP_SRC;
- else op = PIXMAN_OP_OVER;
-
- pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0,
- dx, dy, dw, dh);
-cant_convert:
- if (src_img) pixman_image_unref(src_img);
- if (dst_img) pixman_image_unref(dst_img);
-
- _e_comp_wl_video_buffer_access_data_end(srcbuf);
- _e_comp_wl_video_buffer_access_data_end(dstbuf);
-}
-
-EINTERN Eina_Bool
-e_comp_wl_video_buffer_copy(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf)
-{
- int i, j, c_height;
- unsigned char *s, *d;
-
- EINA_SAFETY_ON_FALSE_RETURN_VAL(VBUF_IS_VALID(srcbuf), EINA_FALSE);
- EINA_SAFETY_ON_FALSE_RETURN_VAL(VBUF_IS_VALID(dstbuf), EINA_FALSE);
-
- if (!_e_comp_wl_video_buffer_access_data_begin(srcbuf))
- return EINA_FALSE;
- if (!_e_comp_wl_video_buffer_access_data_begin(dstbuf))
- {
- _e_comp_wl_video_buffer_access_data_end(srcbuf);
- return EINA_FALSE;
- }
-
- switch (srcbuf->tbmfmt)
- {
- case TBM_FORMAT_ARGB8888:
- case TBM_FORMAT_XRGB8888:
- case TBM_FORMAT_YUV422:
- case TBM_FORMAT_YVU422:
- s = (unsigned char*)srcbuf->ptrs[0];
- d = (unsigned char*)dstbuf->ptrs[0];
- for (i = 0; i < srcbuf->height; i++)
- {
- memcpy(d, s, srcbuf->pitches[0]);
- s += srcbuf->pitches[0];
- d += dstbuf->pitches[0];
- }
- break;
- case TBM_FORMAT_YUV420:
- case TBM_FORMAT_YVU420:
- for (i = 0; i < 3; i++)
- {
- s = (unsigned char*)srcbuf->ptrs[i] + srcbuf->offsets[i];
- d = (unsigned char*)dstbuf->ptrs[i] + dstbuf->offsets[i];
- c_height = (i == 0) ? srcbuf->height : srcbuf->height / 2;
- for (j = 0; j < c_height; j++)
- {
- memcpy(d, s, srcbuf->pitches[i]);
- s += srcbuf->pitches[i];
- d += dstbuf->pitches[i];
- }
- }
- break;
- case TBM_FORMAT_NV12:
- case TBM_FORMAT_NV21:
- for (i = 0; i < 2; i++)
- {
- s = (unsigned char*)srcbuf->ptrs[i] + srcbuf->offsets[i];
- d = (unsigned char*)dstbuf->ptrs[i] + dstbuf->offsets[i];
- c_height = (i == 0) ? srcbuf->height : srcbuf->height / 2;
- for (j = 0; j < c_height; j++)
- {
- memcpy(d, s, srcbuf->pitches[i]);
- s += srcbuf->pitches[i];
- d += dstbuf->pitches[i];
- }
- }
- break;
- default:
- ERR("not implemented for %c%c%c%c", FOURCC_STR(srcbuf->tbmfmt));
- _e_comp_wl_video_buffer_access_data_end(srcbuf);
- _e_comp_wl_video_buffer_access_data_end(dstbuf);
-
- return EINA_FALSE;
- }
-
- _e_comp_wl_video_buffer_access_data_end(srcbuf);
- _e_comp_wl_video_buffer_access_data_end(dstbuf);
-
- return EINA_TRUE;
-}
-
-EINTERN uint
-e_comp_wl_video_buffer_get_mills(void)
-{
- struct timespec tp;
-
- clock_gettime(CLOCK_MONOTONIC, &tp);
-
- return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
-}
-
-EINTERN int
-e_comp_wl_video_buffer_list_length(void)
-{
- return eina_list_count(vbuf_lists);
-}
-
-EINTERN void
-e_comp_wl_video_buffer_list_print(const char *log_path)
-{
- E_Comp_Wl_Video_Buf *vbuf;
- Eina_List *l;
- FILE *log_fl;
-
- log_fl = fopen(log_path, "a");
- if (!log_fl)
- {
- ERR("failed: open file(%s)", log_path);
- return;
- }
-
- setvbuf(log_fl, NULL, _IOLBF, 512);
-
- fprintf(log_fl, "* Video Buffers:\n");
- fprintf(log_fl, "stamp\tsize\tformat\thandles\tpitches\toffsets\tin_use\n");
- EINA_LIST_FOREACH(vbuf_lists, l, vbuf)
- {
- fprintf(log_fl, "%d\t%dx%d\t%c%c%c%c\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d\n",
- vbuf->stamp, vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
- vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
- vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
- vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2],
- vbuf->in_use);
- }
-
- fclose(log_fl);
-}
-
-EINTERN void
-e_comp_wl_video_buffer_size_get(E_Client *ec, int *bw, int *bh)
-{
- E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(ec->pixmap);
-
- if (bw) *bw = 0;
- if (bh) *bh = 0;
-
- if (!buffer)
- {
- INF("no buffer. using ec(%p) size(%dx%d)", ec, ec->w, ec->h);
- if (bw) *bw = ec->w;
- if (bh) *bh = ec->h;
- return;
- }
-
- if (buffer->type == E_COMP_WL_BUFFER_TYPE_VIDEO)
- {
- tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL, buffer->resource);
-
- if (bw) *bw = tbm_surface_get_width(tbm_surface);
- if (bh) *bh = tbm_surface_get_height(tbm_surface);
- }
- else
- {
- if (bw) *bw = buffer->w;
- if (bh) *bh = buffer->h;
- }
-}
-
-EINTERN void
-e_comp_wl_video_buffer_transform_scale_size_get(E_Client *ec, int *bw, int *bh)
-{
- E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(ec->pixmap);
- E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
- int w, h, transform;
-
- if (bw) *bw = 0;
- if (bh) *bh = 0;
-
- if (!buffer)
- {
- INF("no buffer. using ec(%p) size(%dx%d)", ec, ec->w, ec->h);
- if (bw) *bw = ec->w;
- if (bh) *bh = ec->h;
- return;
- }
-
- if (buffer->type == E_COMP_WL_BUFFER_TYPE_VIDEO)
- {
- tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL, buffer->resource);
-
- w = tbm_surface_get_width(tbm_surface);
- h = tbm_surface_get_height(tbm_surface);
- }
- else
- {
- w = buffer->w;
- h = buffer->h;
- }
-
- transform = e_comp_wl_output_buffer_transform_get(ec);
-
- switch (transform)
- {
- case WL_OUTPUT_TRANSFORM_90:
- case WL_OUTPUT_TRANSFORM_270:
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- if (bw) *bw = h / vp->buffer.scale;
- if (bh) *bh = w / vp->buffer.scale;
- break;
- default:
- if (bw) *bw = w / vp->buffer.scale;
- if (bh) *bh = h / vp->buffer.scale;
- break;
- }
-}
+++ /dev/null
-#ifdef E_TYPEDEFS
-
-typedef enum _E_Comp_Wl_Video_Buf_Type
-{
- E_COMP_WL_VIDEO_BUF_TYPE_SHM,
- E_COMP_WL_VIDEO_BUF_TYPE_TBM,
-} E_Comp_Wl_Video_Buf_Type;
-
-typedef struct _E_Comp_Wl_Video_Buf E_Comp_Wl_Video_Buf;
-
-#else
-#ifndef E_COMP_WL_VIDEO_BUFFER_H
-#define E_COMP_WL_VIDEO_BUFFER_H
-
-#include "e_comp_wl_tbm.h"
-
-struct _E_Comp_Wl_Video_Buf
-{
- /* to manage lifecycle */
- uint ref_cnt;
-
- /* to check valid */
- uint stamp;
-
- /* to manage wl_resource */
- struct wl_resource *resource;
- struct wl_listener destroy_listener;
-
- Eina_Bool buffer_destroying;
-
- E_Comp_Wl_Video_Buf_Type type;
- tbm_surface_h tbm_surface;
-
- /* pitch contains the full buffer width.
- * width indicates the content area width.
- */
- tbm_format tbmfmt;
- int width;
- int height;
- uint handles[4];
- uint pitches[4];
- uint offsets[4];
- int names[4];
- void *ptrs[4];
-
- int width_from_pitch;
- int height_from_size;
-
- /* to avoid reading & write at same time */
- Eina_Bool in_use;
-
- Eina_List *free_funcs;
-
- /* for wl_buffer.release event */
- E_Comp_Wl_Buffer *comp_buffer;
- E_Comp_Wl_Buffer_Ref buffer_ref;
- Eina_Rectangle content_r; /* content rect */
- unsigned int content_t; /* content transform */
-};
-
-EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_create(struct wl_resource *resource);
-EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_create_comp(E_Comp_Wl_Buffer *comp_buffer);
-EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_create_tbm(tbm_surface_h tbm_surface);
-EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_alloc(int width, int height, tbm_format tbmfmt, Eina_Bool scanout);
-EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_ref(E_Comp_Wl_Video_Buf *vbuf);
-EINTERN void e_comp_wl_video_buffer_unref(E_Comp_Wl_Video_Buf *vbuf);
-EINTERN Eina_Bool e_comp_wl_video_buffer_valid(E_Comp_Wl_Video_Buf *vbuf);
-
-#define VBUF_IS_VALID(b) e_comp_wl_video_buffer_valid(b)
-#define MSTAMP(b) ((b)?(b)->stamp:0)
-
-#define e_comp_wl_video_buffer_set_use(b, v) \
- do { \
- if (b) b->in_use = v; \
- } while (0)
-
-typedef void (*VBuf_Free_Func) (E_Comp_Wl_Video_Buf *vbuf, void *data);
-EINTERN void e_comp_wl_video_buffer_free_func_add(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data);
-EINTERN void e_comp_wl_video_buffer_free_func_del(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data);
-
-EINTERN void e_comp_wl_video_buffer_clear(E_Comp_Wl_Video_Buf *vbuf);
-EINTERN Eina_Bool e_comp_wl_video_buffer_copy(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf);
-EINTERN void e_comp_wl_video_buffer_convert(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf,
- int sx, int sy, int sw, int sh,
- int dx, int dy, int dw, int dh,
- Eina_Bool over, int rotate, int hflip, int vflip);
-
-EINTERN uint e_comp_wl_video_buffer_get_mills(void);
-EINTERN int e_comp_wl_video_buffer_list_length(void);
-EINTERN void e_comp_wl_video_buffer_list_print(const char *log_path);
-
-EINTERN void e_comp_wl_video_buffer_size_get(E_Client *ec, int *bw, int *bh);
-EINTERN void e_comp_wl_video_buffer_transform_scale_size_get(E_Client *ec, int *bw, int *bh);
-
-#endif
-#endif
#endif
#include "e_comp_wl_rsm.h"
#include "e_comp_wl_screenshooter.h"
-#include "e_comp_wl_video.h"
-#include "e_comp_wl_video_buffer.h"
#include "e_comp_wl_viewport.h"
#include "e_comp_wl_shell.h"
#include "e_policy.h"
#include "e_dbus_conn.h"
#include "e_xdg_shell_v6.h"
#include "e_devicemgr.h"
+
+#include "video/e_video_debug.h"
+#include "video/e_client_video.h"
+#include "video/e_zone_video.h"
+#include "video/e_comp_wl_video.h"
+#include "video/e_comp_wl_video_buffer.h"
--- /dev/null
+#include "e_video_internal.h"
+
+#define EO_DATA_KEY "E_Client_Video"
+
+#define INTERNAL_DATA_GET \
+ E_Client_Video *ecv; \
+ ecv = evas_object_data_get(ec->frame, EO_DATA_KEY)
+
+#define API_ENTRY \
+ INTERNAL_DATA_GET; \
+ EINA_SAFETY_ON_NULL_RETURN(ecv)
+
+#define API_ENTRY_RET(ret) \
+ INTERNAL_DATA_GET; \
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, ret)
+
+typedef struct _E_Client_Video E_Client_Video;
+
+struct _E_Client_Video
+{
+ /* Composite interface ( hwc planes / hwc windows / fallback ) */
+ E_Video_Comp_Iface *iface;
+
+ E_Client *ec;
+
+ Ecore_Event_Handler *eeh_zone_set;
+};
+
+static void
+_e_client_video_comp_iface_deinit(E_Client_Video *ecv)
+{
+ ecv->iface->destroy(ecv->iface);
+ ecv->iface = NULL;
+}
+
+static Eina_Bool
+_e_client_video_comp_iface_init(E_Client_Video *ecv, E_Client *ec)
+{
+ E_Video_Comp_Iface *iface = NULL;
+ E_Output *eout;
+ E_Hwc_Policy hwc_pol;
+
+ if ((e_config->eom_enable == EINA_TRUE) && (e_eom_is_ec_external(ec)))
+ {
+ /* FIXME workaround
+ * eom will be handled by hwc_planes implementation for now */
+ INF("Try to intialize the eom interface");
+ iface = e_video_hwc_planes_iface_create(ec);
+ goto end;
+ }
+
+ if (e_video_debug_display_primary_plane_value_get())
+ {
+ INF("Select SW Compositing mode according to configuration");
+ goto end;
+ }
+
+ eout = e_output_find(ec->zone->output_id);
+ if (!eout)
+ {
+ ERR("Something wrong, couldn't find 'E_Output' from 'E_Zone'");
+ goto end;
+ }
+
+ hwc_pol = e_hwc_policy_get(eout->hwc);
+ if (hwc_pol == E_HWC_POLICY_WINDOWS)
+ {
+ /* TODO */
+ INF("Try to initialize the interface for HWC WINDOWS mode");
+ WRN("* Not Implemented *");
+ iface = NULL;
+ }
+ else if (hwc_pol == E_HWC_POLICY_PLANES)
+ iface = e_video_hwc_planes_iface_create(ec);
+
+end:
+ if (!iface)
+ {
+ iface = e_video_fallback_iface_create(ec);
+ if (!iface)
+ {
+ ERR("Failed to create 'E_Video_Comp_Iface'");
+ return EINA_FALSE;
+ }
+ }
+
+ ecv->iface = iface;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_client_video_cb_ec_zone_set(void *data, int type EINA_UNUSED, void *event)
+{
+ E_Client_Video *ecv;
+ E_Event_Client_Zone_Set *ev;
+
+ ecv = data;
+ ev = event;
+
+ if (ecv->ec != ev->ec)
+ goto end;
+
+ /* TODO
+ * if compositing policy of given E_Zone is changed, de-initialize previous
+ * compositing interface and initialize new compositing interface. */
+
+end:
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_client_video_init(E_Client_Video *ecv, E_Client *ec)
+{
+ Eina_Bool res;
+
+ res = _e_client_video_comp_iface_init(ecv, ec);
+ if (!res)
+ {
+ ERR("Failed to initialize the composition interface for video");
+ return EINA_FALSE;
+ }
+
+ ecv->ec = ec;
+ ecv->eeh_zone_set = ecore_event_handler_add(E_EVENT_CLIENT_ZONE_SET,
+ _e_client_video_cb_ec_zone_set,
+ ecv);
+
+ return EINA_TRUE;
+}
+
+static void
+_e_client_video_deinit(E_Client_Video *ecv)
+{
+ _e_client_video_comp_iface_deinit(ecv);
+
+ E_FREE_FUNC(ecv->eeh_zone_set, ecore_event_handler_del);
+}
+
+EINTERN Eina_Bool
+e_client_video_set(E_Client *ec)
+{
+ E_Client_Video *ecv;
+ Eina_Bool res;
+
+ ELOGF("VIDEO", "<INF> video set", ec->pixmap, ec);
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
+
+ if (e_object_is_del(E_OBJECT(ec)))
+ {
+ ERR("Can't handle deleted client (%p)", ec);
+ return EINA_FALSE;
+ }
+
+ ecv = evas_object_data_get(ec->frame, EO_DATA_KEY);
+ if (ecv)
+ {
+ ERR("Given client (%p) was already set as Video client", ec);
+ return EINA_FALSE;
+ }
+
+ ecv = E_NEW(E_Client_Video, 1);
+ if (!ecv)
+ {
+ ERR("Failed to allocate memory");
+ return EINA_FALSE;
+ }
+
+ res = _e_client_video_init(ecv, ec);
+ if (!res)
+ {
+ ERR("Failed to initialize video setting");
+ free(ecv);
+ return EINA_FALSE;
+ }
+
+ evas_object_data_set(ec->frame, EO_DATA_KEY, ecv);
+ e_object_ref(E_OBJECT(ec));
+
+ return EINA_TRUE;
+}
+
+EINTERN void
+e_client_video_unset(E_Client *ec)
+{
+ API_ENTRY;
+
+ ELOGF("VIDEO", "<INF> unset video", ec->pixmap, ec);
+
+ _e_client_video_deinit(ecv);
+
+ evas_object_data_del(ec->frame, EO_DATA_KEY);
+ e_object_unref(E_OBJECT(ec));
+
+ free(ecv);
+}
+
+EINTERN Eina_Bool
+e_client_video_topmost_visibility_follow(E_Client *ec)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> follow topmost visibility", ec->pixmap, ec);
+
+ if (!ecv->iface->follow_topmost_visibility)
+ return EINA_FALSE;
+
+ return ecv->iface->follow_topmost_visibility(ecv->iface);
+}
+
+EINTERN Eina_Bool
+e_client_video_topmost_visibility_unfollow(E_Client *ec)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> unfollow topmost visibility", ec->pixmap, ec);
+
+ if (!ecv->iface->unfollow_topmost_visibility)
+ return EINA_FALSE;
+
+ return ecv->iface->unfollow_topmost_visibility(ecv->iface);
+}
+
+EINTERN Eina_Bool
+e_client_video_property_allow(E_Client *ec)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> allowed property", ec->pixmap, ec);
+
+ if (!ecv->iface->allowed_property)
+ return EINA_FALSE;
+
+ return ecv->iface->allowed_property(ecv->iface);
+}
+
+EINTERN Eina_Bool
+e_client_video_property_disallow(E_Client *ec)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> disallowed property", ec->pixmap, ec);
+
+ if (!ecv->iface->disallowed_property)
+ return EINA_FALSE;
+
+ return ecv->iface->disallowed_property(ecv->iface);
+}
+
+EINTERN Eina_Bool
+e_client_video_property_get(E_Client *ec, unsigned int id, tdm_value *value)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> get property", ec->pixmap, ec);
+
+ if (!ecv->iface->property_get)
+ return EINA_FALSE;
+
+ return ecv->iface->property_get(ecv->iface, id, value);
+}
+
+EINTERN Eina_Bool
+e_client_video_property_set(E_Client *ec, unsigned int id, tdm_value value)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> set property", ec->pixmap, ec);
+
+ if (!ecv->iface->property_set)
+ return EINA_FALSE;
+
+ return ecv->iface->property_set(ecv->iface, id, value);
+}
+
+EINTERN Eina_Bool
+e_client_video_property_delay_set(E_Client *ec, unsigned int id, tdm_value value)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> delay set property", ec->pixmap, ec);
+
+ if (!ecv->iface->property_delay_set)
+ return EINA_FALSE;
+
+ return ecv->iface->property_delay_set(ecv->iface, id, value);
+}
+
+EINTERN Eina_Bool
+e_client_video_available_properties_get(E_Client *ec, const tdm_prop **props, int *count)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> get available properties", ec->pixmap, ec);
+
+ if (!ecv->iface->available_properties_get)
+ return EINA_FALSE;
+
+ return ecv->iface->available_properties_get(ecv->iface, props, count);
+}
+
+EINTERN Eina_Bool
+e_client_video_info_get(E_Client *ec, E_Client_Video_Info *info)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> get info", ec->pixmap, ec);
+
+ if (!ecv->iface->info_get)
+ return EINA_FALSE;
+
+ return ecv->iface->info_get(ecv->iface, info);
+}
+
+EINTERN Eina_Bool
+e_client_video_commit_data_release(E_Client *ec, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
+{
+ API_ENTRY_RET(EINA_FALSE);
+
+ ELOGF("VIDEO", "<INF> release commit data", ec->pixmap, ec);
+
+ if (!ecv->iface->commit_data_release)
+ return EINA_FALSE;
+
+ return ecv->iface->commit_data_release(ecv->iface, sequence, tv_sec, tv_usec);
+}
+
+EINTERN tbm_surface_h
+e_client_video_tbm_surface_get(E_Client *ec)
+{
+ API_ENTRY_RET(NULL);
+
+ ELOGF("VIDEO", "<INF> get tbm_surface_h", ec->pixmap, ec);
+
+ if (!ecv->iface->tbm_surface_get)
+ return NULL;
+
+ return ecv->iface->tbm_surface_get(ecv->iface);
+}
--- /dev/null
+#ifndef _E_CLIENT_VIDEO_H_
+#define _E_CLIENT_VIDEO_H_
+
+#include <tdm.h>
+#include <tdm_helper.h>
+#include <tbm_surface.h>
+#include <values.h>
+
+typedef struct _E_Client_Video_Info E_Client_Video_Info;
+
+struct _E_Client_Video_Info
+{
+ tdm_info_config src_config;
+ tdm_pos dst_pos;
+ tdm_transform transform;
+};
+
+EINTERN Eina_Bool e_client_video_set(E_Client *ec);
+EINTERN void e_client_video_unset(E_Client *ec);
+
+EINTERN Eina_Bool e_client_video_topmost_visibility_follow(E_Client *ec);
+EINTERN Eina_Bool e_client_video_topmost_visibility_unfollow(E_Client *ec);
+EINTERN Eina_Bool e_client_video_property_allow(E_Client *ec);
+EINTERN Eina_Bool e_client_video_property_disallow(E_Client *ec);
+
+EINTERN Eina_Bool e_client_video_available_properties_get(E_Client *ec, const tdm_prop **props, int *count);
+EINTERN Eina_Bool e_client_video_property_get(E_Client *ec, unsigned int id, tdm_value *value);
+EINTERN Eina_Bool e_client_video_property_set(E_Client *ec, unsigned int id, tdm_value value);
+EINTERN Eina_Bool e_client_video_property_delay_set(E_Client *ec, unsigned int id, tdm_value value);
+
+EINTERN Eina_Bool e_client_video_info_get(E_Client *ec, E_Client_Video_Info *info);
+EINTERN Eina_Bool e_client_video_commit_data_release(E_Client *ec, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
+
+EINTERN tbm_surface_h e_client_video_tbm_surface_get(E_Client *ec);
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e.h"
+#include <tdm.h>
+#include <values.h>
+#include <tdm_helper.h>
+#include <wayland-tbm-server.h>
+#include <tizen-extension-server-protocol.h>
+
+static int _video_detail_log_dom = -1;
+
+#define VER(fmt, arg...) ELOGF("VIDEO", "<ERR> window(0x%08"PRIxPTR"): "fmt, \
+ video->ec->pixmap, video->ec, video->window, ##arg)
+#define VWR(fmt, arg...) ELOGF("VIDEO", "<WRN> window(0x%08"PRIxPTR"): "fmt, \
+ video->ec->pixmap, video->ec, video->window, ##arg)
+#define VIN(fmt, arg...) ELOGF("VIDEO", "<INF> window(0x%08"PRIxPTR"): "fmt, \
+ video->ec->pixmap, video->ec, video->window, ##arg)
+#define VDB(fmt, arg...) DBG("window(0x%08"PRIxPTR") ec(%p): "fmt, video->window, video->ec, ##arg)
+
+#define DET(...) EINA_LOG_DOM_DBG(_video_detail_log_dom, __VA_ARGS__)
+#define VDT(fmt, arg...) DET("window(0x%08"PRIxPTR"): "fmt, video->window, ##arg)
+
+typedef struct _E_Video E_Video;
+
+struct _E_Video
+{
+ struct wl_resource *video_object;
+ struct wl_resource *surface;
+ E_Client *ec;
+ Ecore_Window window;
+
+ Eina_Bool follow_topmost_visibility;
+ Eina_Bool allowed_attribute;
+
+};
+
+static Eina_List *video_list = NULL;
+
+static void _e_video_set(E_Video *video, E_Client *ec);
+static void _e_video_destroy(E_Video *video);
+
+static E_Video *
+find_video_with_surface(struct wl_resource *surface)
+{
+ E_Video *video;
+ Eina_List *l;
+ EINA_LIST_FOREACH(video_list, l, video)
+ {
+ if (video->surface == surface)
+ return video;
+ }
+ return NULL;
+}
+
+static E_Client *
+find_offscreen_parent_get(E_Client *ec)
+{
+ E_Client *parent = NULL;
+
+ if (!ec->comp_data || !ec->comp_data->sub.data)
+ return NULL;
+
+ parent = ec->comp_data->sub.data->parent;
+ while (parent)
+ {
+ if (!parent->comp_data || !parent->comp_data->sub.data)
+ return NULL;
+
+ if (parent->comp_data->sub.data->remote_surface.offscreen_parent)
+ return parent->comp_data->sub.data->remote_surface.offscreen_parent;
+
+ parent = parent->comp_data->sub.data->parent;
+ }
+
+ return NULL;
+}
+
+static int
+_e_video_get_prop_id(E_Video *video, const char *name)
+{
+ const tdm_prop *props;
+ int i, count = 0;
+
+ e_client_video_available_properties_get(video->ec, &props, &count);
+ for (i = 0; i < count; i++)
+ {
+ if (!strncmp(name, props[i].name, TDM_NAME_LEN))
+ {
+ VDB("check property(%s)", name);
+ return props[i].id;
+ }
+ }
+
+ return -1;
+}
+
+static Eina_Bool
+_e_video_is_visible(E_Video *video)
+{
+ E_Client *offscreen_parent;
+
+ if (e_object_is_del(E_OBJECT(video->ec))) return EINA_FALSE;
+
+ if (!e_pixmap_resource_get(video->ec->pixmap))
+ {
+ VDB("no comp buffer");
+ return EINA_FALSE;
+ }
+
+ if (video->ec->comp_data->sub.data && video->ec->comp_data->sub.data->stand_alone)
+ return EINA_TRUE;
+
+ offscreen_parent = find_offscreen_parent_get(video->ec);
+ if (offscreen_parent && offscreen_parent->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED)
+ {
+ VDB("video surface invisible: offscreen fully obscured");
+ return EINA_FALSE;
+ }
+
+ if (!evas_object_visible_get(video->ec->frame))
+ {
+ VDB("evas obj invisible");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EINTERN void
+e_comp_wl_video_hwc_window_commit_data_release(E_Hwc_Window *hwc_window, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec)
+{
+ E_Client *ec = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(hwc_window);
+
+ ec = hwc_window->ec;
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+
+ e_client_video_commit_data_release(ec, sequence, tv_sec, tv_usec);
+}
+
+EINTERN tbm_surface_h
+e_comp_wl_video_hwc_widow_surface_get(E_Hwc_Window *hwc_window)
+{
+ E_Client *ec = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, NULL);
+
+ if (!e_hwc_window_is_video(hwc_window))
+ {
+ ERR("ehw:%p is NOT Video HWC window.", hwc_window);
+ return NULL;
+ }
+
+ ec = hwc_window->ec;
+ if (!ec) return NULL;
+
+ return e_client_video_tbm_surface_get(ec);
+}
+
+EINTERN Eina_Bool
+e_comp_wl_video_hwc_window_info_get(E_Hwc_Window *hwc_window, tdm_hwc_window_info *hwc_win_info)
+{
+ E_Client *ec = NULL;
+ E_Client_Video_Info vinfo;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
+
+ if (!e_hwc_window_is_video(hwc_window))
+ {
+ ERR("ehw:%p is NOT Video HWC window.", hwc_window);
+ return EINA_FALSE;
+ }
+
+ ec = hwc_window->ec;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ if (!e_client_video_info_get(ec, &vinfo))
+ return EINA_FALSE;
+
+ memcpy(&hwc_win_info->src_config, &vinfo.src_config, sizeof(tdm_info_config));
+ memcpy(&hwc_win_info->dst_pos, &vinfo.dst_pos, sizeof(tdm_pos));
+ hwc_win_info->transform = vinfo.transform;
+
+ return EINA_TRUE;
+}
+
+static E_Video *
+_e_video_create(struct wl_resource *video_object, struct wl_resource *surface)
+{
+ E_Video *video;
+ E_Client *ec;
+
+ ec = wl_resource_get_user_data(surface);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(ec)), NULL);
+
+ video = calloc(1, sizeof *video);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(video, NULL);
+
+ video->video_object = video_object;
+ video->surface = surface;
+
+ VIN("create. ec(%p) wl_surface@%d", ec, wl_resource_get_id(video->surface));
+
+ video_list = eina_list_append(video_list, video);
+
+ _e_video_set(video, ec);
+
+ return video;
+}
+
+static void
+_e_video_set(E_Video *video, E_Client *ec)
+{
+ Eina_Bool res;
+ int minw = -1, minh = -1, maxw = -1, maxh = -1;
+ int align = -1;
+ int i, count = 0;
+ const tdm_prop *props;
+
+ video->ec = ec;
+ video->window = e_client_util_win_get(ec);
+
+ EINA_SAFETY_ON_NULL_RETURN(video->ec->zone);
+
+ e_client_video_set(ec);
+ /* FIXME workaround */
+ if ((e_config->eom_enable == EINA_TRUE) &&
+ (e_eom_is_ec_external(ec)))
+ return;
+
+ res = e_zone_video_available_size_get(ec->zone, &minw, &minh, &maxw, &maxh, &align);
+ if (res)
+ {
+ tizen_video_object_send_size(video->video_object,
+ minw, minh, maxw, maxh, align);
+ /* VIN("align width: output(%d) pp(%d) video(%d)",
+ video->output_align, video->pp_align, video->video_align); */
+ }
+ else
+ VER("Failed to get video available size");
+
+ e_client_video_available_properties_get(ec, &props, &count);
+ for (i = 0; i < count; i++)
+ {
+ tdm_value value;
+
+ res = e_client_video_property_get(ec, props[i].id, &value);
+ if (!res)
+ {
+ VER("Failed to get property name %s value %d", props[i].name, value.u32);
+ continue;
+ }
+
+ tizen_video_object_send_attribute(video->video_object, props[i].name, value.u32);
+ }
+}
+
+static void
+_e_video_destroy(E_Video *video)
+{
+ if (!video)
+ return;
+
+ VIN("destroy");
+
+ wl_resource_set_destructor(video->video_object, NULL);
+
+ e_client_video_unset(video->ec);
+
+ video_list = eina_list_remove(video_list, video);
+
+ free(video);
+
+#if 0
+ if (e_comp_wl_video_buffer_list_length() > 0)
+ e_comp_wl_video_buffer_list_print(NULL);
+#endif
+}
+
+static Eina_Bool
+_e_video_cb_ec_remove(void *data, int type, void *event)
+{
+ E_Event_Client *ev = event;
+ E_Client *ec;
+ E_Video *video;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+ ec = ev->ec;
+ if (!ec->comp_data) return ECORE_CALLBACK_PASS_ON;
+
+ video = find_video_with_surface(ec->comp_data->surface);
+ if (!video) return ECORE_CALLBACK_PASS_ON;
+
+ _e_video_destroy(video);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_e_comp_wl_video_object_destroy(struct wl_resource *resource)
+{
+ E_Video *video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ _e_video_destroy(video);
+}
+
+static void
+_e_comp_wl_video_object_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+_e_comp_wl_video_object_cb_set_attribute(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *name,
+ int32_t value)
+{
+ E_Video *video;
+ tdm_value v;
+ int id;
+
+ video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ if(video->ec)
+ VDT("Client(%s):PID(%d) RscID(%d) Attribute:%s, Value:%d",
+ e_client_util_name_get(video->ec) ?: "No Name",
+ video->ec->netwm.pid, wl_resource_get_id(video->surface),
+ name, value);
+
+ // check available property & count
+ id = _e_video_get_prop_id(video, name);
+ if(id < 0)
+ {
+ VIN("no available property");
+ return;
+ }
+
+ v.u32 = value;
+ if ((!_e_video_is_visible(video)) &&
+ /* if mute off, need to do it after buffer commit */
+ ((!strncmp(name, "mute", TDM_NAME_LEN)) && (value == 0)))
+ {
+ e_client_video_property_delay_set(video->ec, id, v);
+ return;
+ }
+ else
+ e_client_video_property_set(video->ec, id, v);
+}
+
+static void
+_e_comp_wl_video_object_cb_follow_topmost_visibility(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ E_Video *video;
+
+ video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ if(!video->ec || video->follow_topmost_visibility)
+ return;
+
+ VIN("set follow_topmost_visibility");
+
+ video->follow_topmost_visibility= EINA_TRUE;
+ e_client_video_topmost_visibility_follow(video->ec);
+}
+
+static void
+_e_comp_wl_video_object_cb_unfollow_topmost_visibility(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ E_Video *video;
+
+ video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ if(!video->ec || !video->follow_topmost_visibility)
+ return;
+
+ VIN("set unfollow_topmost_visibility");
+
+ video->follow_topmost_visibility= EINA_FALSE;
+ e_client_video_topmost_visibility_unfollow(video->ec);
+}
+
+static void
+_e_comp_wl_video_object_cb_allowed_attribute(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ E_Video *video;
+
+ video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ if(!video->ec || video->allowed_attribute)
+ return;
+
+ VIN("set allowed_attribute");
+
+ video->allowed_attribute = EINA_TRUE;
+ e_client_video_property_allow(video->ec);
+}
+
+static void
+_e_comp_wl_video_object_cb_disallowed_attribute(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ E_Video *video;
+
+ video = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(video);
+
+ if(!video->ec || !video->allowed_attribute)
+ return;
+
+ VIN("set disallowed_attribute");
+
+ video->allowed_attribute = EINA_FALSE;
+ e_client_video_property_disallow(video->ec);
+}
+
+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_set_attribute,
+ _e_comp_wl_video_object_cb_follow_topmost_visibility,
+ _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,
+};
+
+static void
+_e_comp_wl_video_cb_get_object(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface)
+{
+ E_Video *video;
+ int version = wl_resource_get_version(resource);
+ struct wl_resource *res;
+
+ res = wl_resource_create(client, &tizen_video_object_interface, version, id);
+ if (res == NULL)
+ {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ if (!(video = _e_video_create(res, surface)))
+ {
+ wl_resource_destroy(res);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(res, &_e_comp_wl_video_object_interface,
+ video, _e_comp_wl_video_object_destroy);
+}
+
+static void
+_e_comp_wl_video_cb_get_viewport(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface)
+{
+ E_Client *ec;
+
+ if (!(ec = wl_resource_get_user_data(surface))) return;
+ if (!ec->comp_data) return;
+
+ if (ec->comp_data && ec->comp_data->scaler.viewport)
+ {
+ wl_resource_post_error(resource,
+ TIZEN_VIDEO_ERROR_VIEWPORT_EXISTS,
+ "a viewport for that subsurface already exists");
+ return;
+ }
+
+ if (!e_comp_wl_viewport_create(resource, id, surface))
+ {
+ ERR("Failed to create viewport for wl_surface@%d",
+ wl_resource_get_id(surface));
+ wl_client_post_no_memory(client);
+ return;
+ }
+}
+
+static void
+_e_comp_wl_video_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(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,
+};
+
+static void
+_e_comp_wl_video_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *res;
+ const uint32_t *formats = NULL;
+ int i, count = 0;
+
+ if (!(res = wl_resource_create(client, &tizen_video_interface, version, id)))
+ {
+ ERR("Could not create tizen_video_interface resource: %m");
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(res, &_e_comp_wl_video_interface, NULL, NULL);
+
+ e_comp_screen_available_video_formats_get(&formats, &count);
+ for (i = 0; i < count; i++)
+ tizen_video_send_format(res, formats[i]);
+}
+
+static Eina_List *video_hdlrs;
+
+static void
+_e_comp_wl_vbuf_print(void *data, const char *log_path)
+{
+ e_comp_wl_video_buffer_list_print(log_path);
+}
+
+static void
+_e_comp_wl_video_to_primary(void *data, const char *log_path)
+{
+ Eina_Bool flag;
+
+ flag = e_video_debug_display_primary_plane_value_get();
+ e_video_debug_display_primary_plane_set(!flag);
+}
+
+static void
+_e_comp_wl_video_punch(void *data, const char *log_path)
+{
+ Eina_Bool flag;
+
+ flag = e_video_debug_punch_value_get();
+ e_video_debug_punch_set(!flag);
+}
+
+EINTERN int
+e_comp_wl_video_init(void)
+{
+ e_comp->wl_comp_data->available_hw_accel.underlay = EINA_TRUE;
+ DBG("enable HW underlay");
+
+ e_comp->wl_comp_data->available_hw_accel.scaler = EINA_TRUE;
+ DBG("enable HW scaler");
+
+ if (!e_comp_wl) return 0;
+ if (!e_comp_wl->wl.disp) return 0;
+ if (e_comp->wl_comp_data->video.global) return 1;
+
+ e_info_server_hook_set("vbuf", _e_comp_wl_vbuf_print, NULL);
+ e_info_server_hook_set("video-to-primary", _e_comp_wl_video_to_primary, NULL);
+ e_info_server_hook_set("video-punch", _e_comp_wl_video_punch, NULL);
+
+ _video_detail_log_dom = eina_log_domain_register("e-comp-wl-video", EINA_COLOR_BLUE);
+ if (_video_detail_log_dom < 0)
+ {
+ ERR("Failed eina_log_domain_register()..!\n");
+ return 0;
+ }
+
+ /* 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);
+
+ if (!e_comp->wl_comp_data->video.global)
+ {
+ ERR("Could not add tizen_video to wayland globals");
+ return 0;
+ }
+
+ E_LIST_HANDLER_APPEND(video_hdlrs, E_EVENT_CLIENT_REMOVE,
+ _e_video_cb_ec_remove, NULL);
+
+ return 1;
+}
+
+EINTERN void
+e_comp_wl_video_shutdown(void)
+{
+ e_comp->wl_comp_data->available_hw_accel.underlay = EINA_FALSE;
+ e_comp->wl_comp_data->available_hw_accel.scaler = EINA_FALSE;
+
+ E_FREE_FUNC(e_comp->wl_comp_data->video.global, wl_global_destroy);
+ E_FREE_LIST(video_hdlrs, ecore_event_handler_del);
+
+ e_info_server_hook_set("vbuf", NULL, NULL);
+ e_info_server_hook_set("video-dst-change", NULL, NULL);
+ e_info_server_hook_set("video-to-primary", NULL, NULL);
+ e_info_server_hook_set("video-punch", NULL, NULL);
+
+ eina_log_domain_unregister(_video_detail_log_dom);
+ _video_detail_log_dom = -1;
+}
--- /dev/null
+#ifdef E_TYPEDEFS
+
+#else
+#ifndef E_COMP_WL_VIDEO_H
+#define E_COMP_WL_VIDEO_H
+
+#define E_COMP_WL
+
+EINTERN int e_comp_wl_video_init(void);
+EINTERN void e_comp_wl_video_shutdown(void);
+
+EINTERN void e_comp_wl_video_hwc_window_commit_data_release(E_Hwc_Window *hwc_window, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
+EINTERN tbm_surface_h e_comp_wl_video_hwc_widow_surface_get(E_Hwc_Window *hwc_window);
+EINTERN Eina_Bool e_comp_wl_video_hwc_window_info_get(E_Hwc_Window *hwc_window, tdm_hwc_window_info *hwc_win_info);
+
+#define C(b,m) (((b) >> (m)) & 0xFF)
+#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24)
+#define IS_RGB(f) ((f) == TBM_FORMAT_XRGB8888 || (f) == TBM_FORMAT_ARGB8888)
+#define ROUNDUP(s,c) (((s) + (c-1)) & ~(c-1))
+
+#endif
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "e.h"
+#include <wayland-tbm-server.h>
+#include <sys/mman.h>
+#include <pixman.h>
+#include <tdm_helper.h>
+
+//#define DEBUG_LIFECYCLE
+
+#define BER(fmt,arg...) ERR("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
+#define BWR(fmt,arg...) WRN("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
+#define BIN(fmt,arg...) INF("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
+#define BDB(fmt,arg...) DBG("%d: "fmt, vbuf ? vbuf->stamp : 0, ##arg)
+
+#define VBUF_RETURN_IF_FAIL(cond) \
+ {if (!(cond)) { BER("'%s' failed", #cond); return; }}
+#define VBUF_RETURN_VAL_IF_FAIL(cond, val) \
+ {if (!(cond)) { BER("'%s' failed", #cond); return val; }}
+
+#ifdef DEBUG_LIFECYCLE
+#undef BDB
+#define BDB BIN
+#endif
+
+typedef struct _VBufFreeFuncInfo
+{
+ VBuf_Free_Func func;
+ void *data;
+} VBufFreeFuncInfo;
+
+static void _e_comp_wl_video_buffer_cb_destroy(struct wl_listener *listener, void *data);
+static void _e_comp_wl_video_buffer_free(E_Comp_Wl_Video_Buf *vbuf);
+#define e_comp_wl_video_buffer_free(b) _e_comp_wl_video_buffer_free(b)
+
+static Eina_List *vbuf_lists;
+
+static E_Comp_Wl_Video_Buf*
+_find_vbuf(uint stamp)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l;
+
+ if (!vbuf_lists)
+ return NULL;
+
+ EINA_LIST_FOREACH(vbuf_lists, l, vbuf)
+ {
+ if (vbuf->stamp == stamp)
+ return vbuf;
+ }
+
+ return NULL;
+}
+
+static Eina_Bool
+_e_comp_wl_video_buffer_access_data_begin(E_Comp_Wl_Video_Buf *vbuf)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, EINA_FALSE);
+
+ vbuf->ptrs[0] = vbuf->ptrs[1] = vbuf->ptrs[2] = NULL;
+
+ if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_SHM)
+ {
+ struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(vbuf->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(shm_buffer, EINA_FALSE);
+ vbuf->ptrs[0] = wl_shm_buffer_get_data(shm_buffer);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf->ptrs[0], EINA_FALSE);
+ return EINA_TRUE;
+ }
+ else if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_TBM)
+ {
+ int i, j;
+ tbm_bo bos[4] = {0,};
+
+ for (i = 0; i < 3; i++)
+ {
+ tbm_bo_handle bo_handles;
+
+ bos[i] = tbm_surface_internal_get_bo(vbuf->tbm_surface, i);
+ if (!bos[i]) continue;
+
+ bo_handles = tbm_bo_map(bos[i], TBM_DEVICE_CPU, TBM_OPTION_READ);
+ if (!bo_handles.ptr)
+ {
+ for (j = 0; j < i; j++)
+ tbm_bo_unmap(bos[j]);
+ return EINA_FALSE;
+ }
+
+ vbuf->ptrs[i] = bo_handles.ptr;
+ }
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf->ptrs[0], EINA_FALSE);
+
+ switch(vbuf->tbmfmt)
+ {
+ case TBM_FORMAT_YVU420:
+ case TBM_FORMAT_YUV420:
+ if (!vbuf->ptrs[1])
+ vbuf->ptrs[1] = vbuf->ptrs[0];
+ if (!vbuf->ptrs[2])
+ vbuf->ptrs[2] = vbuf->ptrs[1];
+ break;
+ case TBM_FORMAT_NV12:
+ case TBM_FORMAT_NV21:
+ if (!vbuf->ptrs[1])
+ vbuf->ptrs[1] = vbuf->ptrs[0];
+ break;
+ default:
+ break;
+ }
+
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static void
+_e_comp_wl_video_buffer_access_data_end(E_Comp_Wl_Video_Buf *vbuf)
+{
+ EINA_SAFETY_ON_NULL_RETURN(vbuf);
+
+ if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_SHM)
+ {
+ vbuf->ptrs[0] = NULL;
+ }
+ else if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_TBM)
+ {
+ int i;
+ tbm_bo bos[4] = {0,};
+
+ for (i = 0; i < 3; i++)
+ {
+ bos[i] = tbm_surface_internal_get_bo(vbuf->tbm_surface, i);
+ if (!bos[i]) continue;
+
+ tbm_bo_unmap(bos[i]);
+ vbuf->ptrs[i] = NULL;
+ }
+ }
+}
+
+static E_Comp_Wl_Video_Buf*
+_e_comp_wl_video_buffer_create_res(struct wl_resource *resource)
+{
+ E_Comp_Wl_Video_Buf *vbuf = NULL;
+ struct wl_shm_buffer *shm_buffer;
+ tbm_surface_h tbm_surface;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(resource, NULL);
+
+ vbuf = calloc(1, sizeof(E_Comp_Wl_Video_Buf));
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf != NULL, create_fail);
+
+ vbuf->ref_cnt = 1;
+ vbuf->stamp = e_comp_wl_video_buffer_get_mills();
+ while (_find_vbuf(vbuf->stamp))
+ vbuf->stamp++;
+
+ vbuf->resource = resource;
+
+ if ((shm_buffer = wl_shm_buffer_get(resource)))
+ {
+ uint32_t tbmfmt = wl_shm_buffer_get_format(shm_buffer);
+
+ vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_SHM;
+
+ if (tbmfmt == WL_SHM_FORMAT_ARGB8888)
+ vbuf->tbmfmt = TBM_FORMAT_ARGB8888;
+ else if (tbmfmt == WL_SHM_FORMAT_XRGB8888)
+ vbuf->tbmfmt = TBM_FORMAT_XRGB8888;
+ else
+ vbuf->tbmfmt = tbmfmt;
+
+ vbuf->width = wl_shm_buffer_get_width(shm_buffer);
+ vbuf->height = wl_shm_buffer_get_height(shm_buffer);
+ vbuf->pitches[0] = wl_shm_buffer_get_stride(shm_buffer);
+
+ vbuf->width_from_pitch = vbuf->width;
+ vbuf->height_from_size = vbuf->height;;
+ }
+ else if ((tbm_surface = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, resource)))
+ {
+ int i;
+
+ vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_TBM;
+ vbuf->tbm_surface = tbm_surface;
+ tbm_surface_internal_ref(tbm_surface);
+
+ vbuf->tbmfmt = tbm_surface_get_format(tbm_surface);
+ vbuf->width = tbm_surface_get_width(tbm_surface);
+ vbuf->height = tbm_surface_get_height(tbm_surface);
+
+ /* NOTE Some format such a NVxx and a YUVxxx can have multiple handles */
+ for (i = 0; i < 3; i++)
+ {
+ uint32_t size = 0, offset = 0, pitch = 0;
+ tbm_bo bo;
+
+ bo = tbm_surface_internal_get_bo(tbm_surface, i);
+ if (bo)
+ {
+ vbuf->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf->handles[i] > 0, create_fail);
+
+ vbuf->names[i] = tbm_bo_export(bo);
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf->names[i] > 0, create_fail);
+ }
+
+ tbm_surface_internal_get_plane_data(tbm_surface, i, &size, &offset, &pitch);
+ vbuf->pitches[i] = pitch;
+ vbuf->offsets[i] = offset;
+ }
+
+ tdm_helper_get_buffer_full_size(tbm_surface, &vbuf->width_from_pitch, &vbuf->height_from_size);
+ }
+ else
+ {
+ ERR("unknown buffer resource");
+ goto create_fail;
+ }
+
+ vbuf_lists = eina_list_append(vbuf_lists, vbuf);
+
+ BDB("type(%d) %dx%d(%dx%d), %c%c%c%c, name(%d,%d,%d) hnd(%d,%d,%d), pitch(%d,%d,%d), offset(%d,%d,%d)",
+ vbuf->type, vbuf->width_from_pitch, vbuf->height_from_size,
+ vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
+ vbuf->names[0], vbuf->names[1], vbuf->names[2],
+ vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
+ vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
+ vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2]);
+
+ return vbuf;
+
+create_fail:
+ _e_comp_wl_video_buffer_free(vbuf);
+
+ return NULL;
+}
+
+EINTERN E_Comp_Wl_Video_Buf*
+e_comp_wl_video_buffer_create(struct wl_resource *resource)
+{
+ E_Comp_Wl_Video_Buf *vbuf = _e_comp_wl_video_buffer_create_res(resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+ vbuf->destroy_listener.notify = _e_comp_wl_video_buffer_cb_destroy;
+ wl_resource_add_destroy_listener(resource, &vbuf->destroy_listener);
+
+ return vbuf;
+}
+
+EINTERN E_Comp_Wl_Video_Buf*
+e_comp_wl_video_buffer_create_comp(E_Comp_Wl_Buffer *comp_buffer)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(comp_buffer, NULL);
+
+ vbuf = _e_comp_wl_video_buffer_create_res(comp_buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+ vbuf->comp_buffer = comp_buffer;
+
+ vbuf->destroy_listener.notify = _e_comp_wl_video_buffer_cb_destroy;
+ wl_resource_add_destroy_listener(comp_buffer->resource, &vbuf->destroy_listener);
+
+ return vbuf;
+}
+
+EINTERN E_Comp_Wl_Video_Buf*
+e_comp_wl_video_buffer_create_tbm(tbm_surface_h tbm_surface)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ int i;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, NULL);
+
+ vbuf = calloc(1, sizeof(E_Comp_Wl_Video_Buf));
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf != NULL, create_fail);
+
+ vbuf->ref_cnt = 1;
+ vbuf->stamp = e_comp_wl_video_buffer_get_mills();
+ while (_find_vbuf(vbuf->stamp))
+ vbuf->stamp++;
+
+ vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_TBM;
+ vbuf->tbm_surface = tbm_surface;
+ tbm_surface_internal_ref(tbm_surface);
+
+ vbuf->tbmfmt = tbm_surface_get_format(tbm_surface);
+ vbuf->width = tbm_surface_get_width(tbm_surface);
+ vbuf->height = tbm_surface_get_height(tbm_surface);
+
+ for (i = 0; i < 3; i++)
+ {
+ uint32_t size = 0, offset = 0, pitch = 0;
+ tbm_bo bo;
+
+ bo = tbm_surface_internal_get_bo(tbm_surface, i);
+ if (bo)
+ {
+ vbuf->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf->handles[i] > 0, create_fail);
+
+ vbuf->names[i] = tbm_bo_export(bo);
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf->names[i] > 0, create_fail);
+ }
+
+ tbm_surface_internal_get_plane_data(tbm_surface, i, &size, &offset, &pitch);
+ vbuf->pitches[i] = pitch;
+ vbuf->offsets[i] = offset;
+ }
+
+ tdm_helper_get_buffer_full_size(tbm_surface, &vbuf->width_from_pitch, &vbuf->height_from_size);
+
+ vbuf_lists = eina_list_append(vbuf_lists, vbuf);
+
+ BDB("type(%d) %dx%d(%dx%d), %c%c%c%c, name(%d,%d,%d) hnd(%d,%d,%d), pitch(%d,%d,%d), offset(%d,%d,%d)",
+ vbuf->type, vbuf->width_from_pitch, vbuf->height_from_size,
+ vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
+ vbuf->names[0], vbuf->names[1], vbuf->names[2],
+ vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
+ vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
+ vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2]);
+
+ return vbuf;
+
+create_fail:
+ _e_comp_wl_video_buffer_free(vbuf);
+
+ return NULL;
+}
+
+EINTERN E_Comp_Wl_Video_Buf*
+e_comp_wl_video_buffer_alloc(int width, int height, tbm_format tbmfmt, Eina_Bool scanout)
+{
+ E_Comp_Wl_Video_Buf *vbuf = NULL;
+ tbm_surface_h tbm_surface = NULL;
+ int i;
+
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(width > 0, NULL);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(height > 0, NULL);
+
+ vbuf = calloc(1, sizeof(E_Comp_Wl_Video_Buf));
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf != NULL, alloc_fail);
+
+ vbuf->ref_cnt = 1;
+ vbuf->stamp = e_comp_wl_video_buffer_get_mills();
+ while (_find_vbuf(vbuf->stamp))
+ vbuf->stamp++;
+
+ if (scanout)
+ tbm_surface = tbm_surface_internal_create_with_flags(width, height, tbmfmt, TBM_BO_SCANOUT);
+ else
+ tbm_surface = tbm_surface_internal_create_with_flags(width, height, tbmfmt, TBM_BO_DEFAULT);
+ EINA_SAFETY_ON_NULL_GOTO(tbm_surface, alloc_fail);
+
+ vbuf->type = E_COMP_WL_VIDEO_BUF_TYPE_TBM;
+ vbuf->tbm_surface = tbm_surface;
+ tbm_surface_internal_ref(tbm_surface);
+
+ vbuf->tbmfmt = tbmfmt;
+ vbuf->width = width;
+ vbuf->height = height;
+
+ for (i = 0; i < 3; i++)
+ {
+ uint32_t size = 0, offset = 0, pitch = 0;
+ tbm_bo bo;
+
+ bo = tbm_surface_internal_get_bo(tbm_surface, i);
+ if (bo)
+ {
+ vbuf->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf->handles[i] > 0, alloc_fail);
+
+ vbuf->names[i] = tbm_bo_export(bo);
+ EINA_SAFETY_ON_FALSE_GOTO(vbuf->names[i] > 0, alloc_fail);
+ }
+
+ tbm_surface_internal_get_plane_data(tbm_surface, i, &size, &offset, &pitch);
+ vbuf->pitches[i] = pitch;
+ vbuf->offsets[i] = offset;
+ }
+
+ tdm_helper_get_buffer_full_size(tbm_surface, &vbuf->width_from_pitch, &vbuf->height_from_size);
+
+ tbm_surface_internal_unref(tbm_surface);
+
+ vbuf_lists = eina_list_append(vbuf_lists, vbuf);
+
+ BDB("type(%d) %dx%d(%dx%d) %c%c%c%c nm(%d,%d,%d) hnd(%d,%d,%d) pitch(%d,%d,%d) offset(%d,%d,%d)",
+ vbuf->type, vbuf->width_from_pitch, vbuf->height_from_size,
+ vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
+ vbuf->names[0], vbuf->names[1], vbuf->names[2],
+ vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
+ vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
+ vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2]);
+
+ return vbuf;
+
+alloc_fail:
+ if (tbm_surface)
+ tbm_surface_internal_unref(tbm_surface);
+ _e_comp_wl_video_buffer_free(vbuf);
+ return NULL;
+}
+
+EINTERN E_Comp_Wl_Video_Buf*
+e_comp_wl_video_buffer_ref(E_Comp_Wl_Video_Buf *vbuf)
+{
+ if (!vbuf)
+ return NULL;
+
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(VBUF_IS_VALID(vbuf), NULL);
+
+ vbuf->ref_cnt++;
+ BDB("count(%d) ref", vbuf->ref_cnt);
+
+ return vbuf;
+}
+
+EINTERN void
+e_comp_wl_video_buffer_unref(E_Comp_Wl_Video_Buf *vbuf)
+{
+ if (!vbuf)
+ return;
+
+ VBUF_RETURN_IF_FAIL(e_comp_wl_video_buffer_valid(vbuf));
+
+ vbuf->ref_cnt--;
+ BDB("count(%d) unref", vbuf->ref_cnt);
+
+ if (!vbuf->buffer_destroying && vbuf->ref_cnt == 0)
+ _e_comp_wl_video_buffer_free(vbuf);
+}
+
+static void
+_e_comp_wl_video_buffer_free(E_Comp_Wl_Video_Buf *vbuf)
+{
+ VBufFreeFuncInfo *info;
+ Eina_List *l, *ll;
+
+ if (!vbuf)
+ return;
+
+ VBUF_RETURN_IF_FAIL(e_comp_wl_video_buffer_valid(vbuf));
+
+ BDB("vbuf(%p) tbm_surface(%p) freed", vbuf, vbuf->tbm_surface);
+
+ vbuf->buffer_destroying = EINA_TRUE;
+
+ if (vbuf->destroy_listener.notify)
+ {
+ wl_list_remove(&vbuf->destroy_listener.link);
+ vbuf->destroy_listener.notify = NULL;
+ }
+
+ EINA_LIST_FOREACH_SAFE(vbuf->free_funcs, l, ll, info)
+ {
+ /* call before tmb_bo_unref */
+ vbuf->free_funcs = eina_list_remove_list(vbuf->free_funcs, l);
+ if (info->func)
+ info->func(vbuf, info->data);
+ free(info);
+ }
+
+#if 0
+ /* DO not check ref_count here. Even if ref_count is not 0, vbuf can be
+ * be destroyed by wl_buffer_destroy forcely. video or screenmirror should add
+ * the vbuf free function and handle the destroying vbuf situation.
+ */
+ if (!vbuf->buffer_destroying)
+ VBUF_RETURN_IF_FAIL(vbuf->ref_cnt == 0);
+#endif
+
+ /* make sure all operation is done */
+ VBUF_RETURN_IF_FAIL(vbuf->in_use == EINA_FALSE);
+
+ if (vbuf->type == E_COMP_WL_VIDEO_BUF_TYPE_TBM && vbuf->tbm_surface)
+ {
+ tbm_surface_internal_unref(vbuf->tbm_surface);
+ vbuf->tbm_surface = NULL;
+ }
+
+ vbuf_lists = eina_list_remove(vbuf_lists, vbuf);
+
+ vbuf->stamp = 0;
+
+ free(vbuf);
+}
+
+static void
+_e_comp_wl_video_buffer_cb_destroy(struct wl_listener *listener, void *data)
+{
+ E_Comp_Wl_Video_Buf *vbuf = container_of(listener, E_Comp_Wl_Video_Buf, destroy_listener);
+
+ if (!vbuf) return;
+
+ vbuf->comp_buffer = NULL;
+
+ if (vbuf->buffer_destroying == EINA_FALSE)
+ {
+ vbuf->destroy_listener.notify = NULL;
+ _e_comp_wl_video_buffer_free(vbuf);
+ }
+}
+
+EINTERN void
+e_comp_wl_video_buffer_clear(E_Comp_Wl_Video_Buf *vbuf)
+{
+ EINA_SAFETY_ON_NULL_RETURN(vbuf);
+
+ if (!_e_comp_wl_video_buffer_access_data_begin(vbuf))
+ {
+ BER("can't access ptr");
+ return;
+ }
+
+ switch(vbuf->tbmfmt)
+ {
+ case TBM_FORMAT_ARGB8888:
+ case TBM_FORMAT_XRGB8888:
+ memset(vbuf->ptrs[0], 0, vbuf->pitches[0] * vbuf->height);
+ break;
+ case TBM_FORMAT_YVU420:
+ case TBM_FORMAT_YUV420:
+ memset((char*)vbuf->ptrs[0] + vbuf->offsets[0], 0x10, vbuf->pitches[0] * vbuf->height);
+ memset((char*)vbuf->ptrs[1] + vbuf->offsets[1], 0x80, vbuf->pitches[1] * (vbuf->height >> 1));
+ memset((char*)vbuf->ptrs[2] + vbuf->offsets[2], 0x80, vbuf->pitches[2] * (vbuf->height >> 1));
+ break;
+ case TBM_FORMAT_NV12:
+ case TBM_FORMAT_NV21:
+ memset((char*)vbuf->ptrs[0] + vbuf->offsets[0], 0x10, vbuf->pitches[0] * vbuf->height);
+ memset((char*)vbuf->ptrs[1] + vbuf->offsets[1], 0x80, vbuf->pitches[1] * (vbuf->height >> 1));
+ break;
+ case TBM_FORMAT_YUYV:
+ {
+ int *ibuf = (int*)vbuf->ptrs[0];
+ int i, size = vbuf->pitches[0] * vbuf->height / 4;
+
+ for (i = 0 ; i < size ; i++)
+ ibuf[i] = 0x10801080;
+ }
+ break;
+ case TBM_FORMAT_UYVY:
+ {
+ int *ibuf = (int*)vbuf->ptrs[0];
+ int i, size = vbuf->pitches[0] * vbuf->height / 4;
+
+ for (i = 0 ; i < size ; i++)
+ ibuf[i] = 0x80108010; /* YUYV -> 0xVYUY */
+ }
+ break;
+ default:
+ BWR("can't clear %c%c%c%c buffer", FOURCC_STR(vbuf->tbmfmt));
+ break;
+ }
+
+ _e_comp_wl_video_buffer_access_data_end(vbuf);
+}
+
+EINTERN Eina_Bool
+e_comp_wl_video_buffer_valid(E_Comp_Wl_Video_Buf *vbuf)
+{
+ E_Comp_Wl_Video_Buf *temp;
+ Eina_List *l;
+
+ VBUF_RETURN_VAL_IF_FAIL(vbuf != NULL, EINA_FALSE);
+ VBUF_RETURN_VAL_IF_FAIL(vbuf->stamp != 0, EINA_FALSE);
+
+ EINA_LIST_FOREACH(vbuf_lists, l, temp)
+ {
+ if (temp->stamp == vbuf->stamp)
+ return EINA_TRUE;
+ }
+
+ BDB("vbuf(%p) invalid", vbuf);
+
+ return EINA_FALSE;
+}
+
+static VBufFreeFuncInfo*
+_e_comp_wl_video_buffer_free_func_find(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data)
+{
+ VBufFreeFuncInfo *info;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(vbuf->free_funcs, l, info)
+ {
+ if (info->func == func && info->data == data)
+ return info;
+ }
+
+ return NULL;
+}
+
+EINTERN void
+e_comp_wl_video_buffer_free_func_add(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data)
+{
+ VBufFreeFuncInfo *info;
+
+ EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(vbuf));
+ EINA_SAFETY_ON_NULL_RETURN(func);
+
+ info = _e_comp_wl_video_buffer_free_func_find(vbuf, func, data);
+ if (info)
+ return;
+
+ info = calloc(1, sizeof(VBufFreeFuncInfo));
+ EINA_SAFETY_ON_NULL_RETURN(info);
+
+ info->func = func;
+ info->data = data;
+
+ vbuf->free_funcs = eina_list_append(vbuf->free_funcs, info);
+}
+
+EINTERN void
+e_comp_wl_video_buffer_free_func_del(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data)
+{
+ VBufFreeFuncInfo *info;
+
+ EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(vbuf));
+ EINA_SAFETY_ON_NULL_RETURN(func);
+
+ info = _e_comp_wl_video_buffer_free_func_find(vbuf, func, data);
+ if (!info)
+ return;
+
+ vbuf->free_funcs = eina_list_remove(vbuf->free_funcs, info);
+
+ free(info);
+}
+
+static pixman_format_code_t
+_e_comp_wl_video_buffer_pixman_format_get(E_Comp_Wl_Video_Buf *vbuf)
+{
+ switch(vbuf->tbmfmt)
+ {
+ case TBM_FORMAT_ARGB8888: return PIXMAN_a8r8g8b8;
+ case TBM_FORMAT_XRGB8888: return PIXMAN_x8r8g8b8;
+ default: return 0;
+ }
+ return 0;
+}
+
+EINTERN void
+e_comp_wl_video_buffer_convert(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh,
+ Eina_Bool over, int rotate, int hflip, int vflip)
+{
+ pixman_image_t *src_img = NULL, *dst_img = NULL;
+ pixman_format_code_t src_format, dst_format;
+ double scale_x, scale_y;
+ int rotate_step;
+ pixman_transform_t t;
+ struct pixman_f_transform ft;
+ pixman_op_t op;
+ int src_stride, dst_stride;
+ int buf_width;
+
+ EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(srcbuf));
+ EINA_SAFETY_ON_FALSE_RETURN(VBUF_IS_VALID(dstbuf));
+
+ if (!_e_comp_wl_video_buffer_access_data_begin(srcbuf))
+ return;
+ if (!_e_comp_wl_video_buffer_access_data_begin(dstbuf))
+ {
+ _e_comp_wl_video_buffer_access_data_end(srcbuf);
+ return;
+ }
+
+ /* not handle buffers which have 2 more gem handles */
+ EINA_SAFETY_ON_NULL_GOTO(srcbuf->ptrs[0], cant_convert);
+ EINA_SAFETY_ON_NULL_GOTO(dstbuf->ptrs[0], cant_convert);
+ EINA_SAFETY_ON_FALSE_RETURN(!srcbuf->ptrs[1]);
+ EINA_SAFETY_ON_FALSE_RETURN(!dstbuf->ptrs[1]);
+
+ src_format = _e_comp_wl_video_buffer_pixman_format_get(srcbuf);
+ EINA_SAFETY_ON_FALSE_GOTO(src_format > 0, cant_convert);
+ dst_format = _e_comp_wl_video_buffer_pixman_format_get(dstbuf);
+ EINA_SAFETY_ON_FALSE_GOTO(dst_format > 0, cant_convert);
+
+ buf_width = IS_RGB(srcbuf->tbmfmt)?(srcbuf->pitches[0]/4):srcbuf->pitches[0];
+ src_stride = IS_RGB(srcbuf->tbmfmt)?(srcbuf->pitches[0]):buf_width * (PIXMAN_FORMAT_BPP(src_format) / 8);
+ src_img = pixman_image_create_bits(src_format, buf_width, srcbuf->height,
+ (uint32_t*)srcbuf->ptrs[0], src_stride);
+ EINA_SAFETY_ON_NULL_GOTO(src_img, cant_convert);
+
+ buf_width = IS_RGB(dstbuf->tbmfmt)?(dstbuf->pitches[0]/4):dstbuf->pitches[0];
+ dst_stride = IS_RGB(srcbuf->tbmfmt)?(dstbuf->pitches[0]):buf_width * (PIXMAN_FORMAT_BPP(dst_format) / 8);
+ dst_img = pixman_image_create_bits(dst_format, buf_width, dstbuf->height,
+ (uint32_t*)dstbuf->ptrs[0], dst_stride);
+ EINA_SAFETY_ON_NULL_GOTO(dst_img, cant_convert);
+
+ pixman_f_transform_init_identity(&ft);
+
+ if (hflip)
+ {
+ pixman_f_transform_scale(&ft, NULL, -1, 1);
+ pixman_f_transform_translate(&ft, NULL, dw, 0);
+ }
+
+ if (vflip)
+ {
+ pixman_f_transform_scale(&ft, NULL, 1, -1);
+ pixman_f_transform_translate(&ft, NULL, 0, dh);
+ }
+
+ rotate_step = (rotate + 360) / 90 % 4;
+ if (rotate_step > 0)
+ {
+ int c, s, tx = 0, ty = 0;
+ switch (rotate_step)
+ {
+ case 1:
+ c = 0, s = -1, tx = -dw;
+ break;
+ case 2:
+ c = -1, s = 0, tx = -dw, ty = -dh;
+ break;
+ case 3:
+ c = 0, s = 1, ty = -dh;
+ break;
+ }
+ pixman_f_transform_translate(&ft, NULL, tx, ty);
+ pixman_f_transform_rotate(&ft, NULL, c, s);
+ }
+
+ if (rotate_step % 2 == 0)
+ {
+ scale_x = (double)sw / dw;
+ scale_y = (double)sh / dh;
+ }
+ else
+ {
+ scale_x = (double)sw / dh;
+ scale_y = (double)sh / dw;
+ }
+
+ pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
+ pixman_f_transform_translate(&ft, NULL, sx, sy);
+ pixman_transform_from_pixman_f_transform(&t, &ft);
+ pixman_image_set_transform(src_img, &t);
+
+ if (!over) op = PIXMAN_OP_SRC;
+ else op = PIXMAN_OP_OVER;
+
+ pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0,
+ dx, dy, dw, dh);
+cant_convert:
+ if (src_img) pixman_image_unref(src_img);
+ if (dst_img) pixman_image_unref(dst_img);
+
+ _e_comp_wl_video_buffer_access_data_end(srcbuf);
+ _e_comp_wl_video_buffer_access_data_end(dstbuf);
+}
+
+EINTERN Eina_Bool
+e_comp_wl_video_buffer_copy(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf)
+{
+ int i, j, c_height;
+ unsigned char *s, *d;
+
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(VBUF_IS_VALID(srcbuf), EINA_FALSE);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(VBUF_IS_VALID(dstbuf), EINA_FALSE);
+
+ if (!_e_comp_wl_video_buffer_access_data_begin(srcbuf))
+ return EINA_FALSE;
+ if (!_e_comp_wl_video_buffer_access_data_begin(dstbuf))
+ {
+ _e_comp_wl_video_buffer_access_data_end(srcbuf);
+ return EINA_FALSE;
+ }
+
+ switch (srcbuf->tbmfmt)
+ {
+ case TBM_FORMAT_ARGB8888:
+ case TBM_FORMAT_XRGB8888:
+ case TBM_FORMAT_YUV422:
+ case TBM_FORMAT_YVU422:
+ s = (unsigned char*)srcbuf->ptrs[0];
+ d = (unsigned char*)dstbuf->ptrs[0];
+ for (i = 0; i < srcbuf->height; i++)
+ {
+ memcpy(d, s, srcbuf->pitches[0]);
+ s += srcbuf->pitches[0];
+ d += dstbuf->pitches[0];
+ }
+ break;
+ case TBM_FORMAT_YUV420:
+ case TBM_FORMAT_YVU420:
+ for (i = 0; i < 3; i++)
+ {
+ s = (unsigned char*)srcbuf->ptrs[i] + srcbuf->offsets[i];
+ d = (unsigned char*)dstbuf->ptrs[i] + dstbuf->offsets[i];
+ c_height = (i == 0) ? srcbuf->height : srcbuf->height / 2;
+ for (j = 0; j < c_height; j++)
+ {
+ memcpy(d, s, srcbuf->pitches[i]);
+ s += srcbuf->pitches[i];
+ d += dstbuf->pitches[i];
+ }
+ }
+ break;
+ case TBM_FORMAT_NV12:
+ case TBM_FORMAT_NV21:
+ for (i = 0; i < 2; i++)
+ {
+ s = (unsigned char*)srcbuf->ptrs[i] + srcbuf->offsets[i];
+ d = (unsigned char*)dstbuf->ptrs[i] + dstbuf->offsets[i];
+ c_height = (i == 0) ? srcbuf->height : srcbuf->height / 2;
+ for (j = 0; j < c_height; j++)
+ {
+ memcpy(d, s, srcbuf->pitches[i]);
+ s += srcbuf->pitches[i];
+ d += dstbuf->pitches[i];
+ }
+ }
+ break;
+ default:
+ ERR("not implemented for %c%c%c%c", FOURCC_STR(srcbuf->tbmfmt));
+ _e_comp_wl_video_buffer_access_data_end(srcbuf);
+ _e_comp_wl_video_buffer_access_data_end(dstbuf);
+
+ return EINA_FALSE;
+ }
+
+ _e_comp_wl_video_buffer_access_data_end(srcbuf);
+ _e_comp_wl_video_buffer_access_data_end(dstbuf);
+
+ return EINA_TRUE;
+}
+
+EINTERN uint
+e_comp_wl_video_buffer_get_mills(void)
+{
+ struct timespec tp;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+
+ return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+}
+
+EINTERN int
+e_comp_wl_video_buffer_list_length(void)
+{
+ return eina_list_count(vbuf_lists);
+}
+
+EINTERN void
+e_comp_wl_video_buffer_list_print(const char *log_path)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l;
+ FILE *log_fl;
+
+ log_fl = fopen(log_path, "a");
+ if (!log_fl)
+ {
+ ERR("failed: open file(%s)", log_path);
+ return;
+ }
+
+ setvbuf(log_fl, NULL, _IOLBF, 512);
+
+ fprintf(log_fl, "* Video Buffers:\n");
+ fprintf(log_fl, "stamp\tsize\tformat\thandles\tpitches\toffsets\tin_use\n");
+ EINA_LIST_FOREACH(vbuf_lists, l, vbuf)
+ {
+ fprintf(log_fl, "%d\t%dx%d\t%c%c%c%c\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d\n",
+ vbuf->stamp, vbuf->width, vbuf->height, FOURCC_STR(vbuf->tbmfmt),
+ vbuf->handles[0], vbuf->handles[1], vbuf->handles[2],
+ vbuf->pitches[0], vbuf->pitches[1], vbuf->pitches[2],
+ vbuf->offsets[0], vbuf->offsets[1], vbuf->offsets[2],
+ vbuf->in_use);
+ }
+
+ fclose(log_fl);
+}
+
+EINTERN void
+e_comp_wl_video_buffer_size_get(E_Client *ec, int *bw, int *bh)
+{
+ E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(ec->pixmap);
+
+ if (bw) *bw = 0;
+ if (bh) *bh = 0;
+
+ if (!buffer)
+ {
+ INF("no buffer. using ec(%p) size(%dx%d)", ec, ec->w, ec->h);
+ if (bw) *bw = ec->w;
+ if (bh) *bh = ec->h;
+ return;
+ }
+
+ if (buffer->type == E_COMP_WL_BUFFER_TYPE_VIDEO)
+ {
+ tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL, buffer->resource);
+
+ if (bw) *bw = tbm_surface_get_width(tbm_surface);
+ if (bh) *bh = tbm_surface_get_height(tbm_surface);
+ }
+ else
+ {
+ if (bw) *bw = buffer->w;
+ if (bh) *bh = buffer->h;
+ }
+}
+
+EINTERN void
+e_comp_wl_video_buffer_transform_scale_size_get(E_Client *ec, int *bw, int *bh)
+{
+ E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(ec->pixmap);
+ E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
+ int w, h, transform;
+
+ if (bw) *bw = 0;
+ if (bh) *bh = 0;
+
+ if (!buffer)
+ {
+ INF("no buffer. using ec(%p) size(%dx%d)", ec, ec->w, ec->h);
+ if (bw) *bw = ec->w;
+ if (bh) *bh = ec->h;
+ return;
+ }
+
+ if (buffer->type == E_COMP_WL_BUFFER_TYPE_VIDEO)
+ {
+ tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL, buffer->resource);
+
+ w = tbm_surface_get_width(tbm_surface);
+ h = tbm_surface_get_height(tbm_surface);
+ }
+ else
+ {
+ w = buffer->w;
+ h = buffer->h;
+ }
+
+ transform = e_comp_wl_output_buffer_transform_get(ec);
+
+ switch (transform)
+ {
+ case WL_OUTPUT_TRANSFORM_90:
+ case WL_OUTPUT_TRANSFORM_270:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ if (bw) *bw = h / vp->buffer.scale;
+ if (bh) *bh = w / vp->buffer.scale;
+ break;
+ default:
+ if (bw) *bw = w / vp->buffer.scale;
+ if (bh) *bh = h / vp->buffer.scale;
+ break;
+ }
+}
--- /dev/null
+#ifdef E_TYPEDEFS
+
+typedef enum _E_Comp_Wl_Video_Buf_Type
+{
+ E_COMP_WL_VIDEO_BUF_TYPE_SHM,
+ E_COMP_WL_VIDEO_BUF_TYPE_TBM,
+} E_Comp_Wl_Video_Buf_Type;
+
+typedef struct _E_Comp_Wl_Video_Buf E_Comp_Wl_Video_Buf;
+
+#else
+#ifndef E_COMP_WL_VIDEO_BUFFER_H
+#define E_COMP_WL_VIDEO_BUFFER_H
+
+#include "e_comp_wl_tbm.h"
+
+struct _E_Comp_Wl_Video_Buf
+{
+ /* to manage lifecycle */
+ uint ref_cnt;
+
+ /* to check valid */
+ uint stamp;
+
+ /* to manage wl_resource */
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+
+ Eina_Bool buffer_destroying;
+
+ E_Comp_Wl_Video_Buf_Type type;
+ tbm_surface_h tbm_surface;
+
+ /* pitch contains the full buffer width.
+ * width indicates the content area width.
+ */
+ tbm_format tbmfmt;
+ int width;
+ int height;
+ uint handles[4];
+ uint pitches[4];
+ uint offsets[4];
+ int names[4];
+ void *ptrs[4];
+
+ int width_from_pitch;
+ int height_from_size;
+
+ /* to avoid reading & write at same time */
+ Eina_Bool in_use;
+
+ Eina_List *free_funcs;
+
+ /* for wl_buffer.release event */
+ E_Comp_Wl_Buffer *comp_buffer;
+ E_Comp_Wl_Buffer_Ref buffer_ref;
+ Eina_Rectangle content_r; /* content rect */
+ unsigned int content_t; /* content transform */
+};
+
+EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_create(struct wl_resource *resource);
+EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_create_comp(E_Comp_Wl_Buffer *comp_buffer);
+EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_create_tbm(tbm_surface_h tbm_surface);
+EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_alloc(int width, int height, tbm_format tbmfmt, Eina_Bool scanout);
+EINTERN E_Comp_Wl_Video_Buf* e_comp_wl_video_buffer_ref(E_Comp_Wl_Video_Buf *vbuf);
+EINTERN void e_comp_wl_video_buffer_unref(E_Comp_Wl_Video_Buf *vbuf);
+EINTERN Eina_Bool e_comp_wl_video_buffer_valid(E_Comp_Wl_Video_Buf *vbuf);
+
+#define VBUF_IS_VALID(b) e_comp_wl_video_buffer_valid(b)
+#define MSTAMP(b) ((b)?(b)->stamp:0)
+
+#define e_comp_wl_video_buffer_set_use(b, v) \
+ do { \
+ if (b) b->in_use = v; \
+ } while (0)
+
+typedef void (*VBuf_Free_Func) (E_Comp_Wl_Video_Buf *vbuf, void *data);
+EINTERN void e_comp_wl_video_buffer_free_func_add(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data);
+EINTERN void e_comp_wl_video_buffer_free_func_del(E_Comp_Wl_Video_Buf *vbuf, VBuf_Free_Func func, void *data);
+
+EINTERN void e_comp_wl_video_buffer_clear(E_Comp_Wl_Video_Buf *vbuf);
+EINTERN Eina_Bool e_comp_wl_video_buffer_copy(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf);
+EINTERN void e_comp_wl_video_buffer_convert(E_Comp_Wl_Video_Buf *srcbuf, E_Comp_Wl_Video_Buf *dstbuf,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh,
+ Eina_Bool over, int rotate, int hflip, int vflip);
+
+EINTERN uint e_comp_wl_video_buffer_get_mills(void);
+EINTERN int e_comp_wl_video_buffer_list_length(void);
+EINTERN void e_comp_wl_video_buffer_list_print(const char *log_path);
+
+EINTERN void e_comp_wl_video_buffer_size_get(E_Client *ec, int *bw, int *bh);
+EINTERN void e_comp_wl_video_buffer_transform_scale_size_get(E_Client *ec, int *bw, int *bh);
+
+#endif
+#endif
--- /dev/null
+#include "e_video_internal.h"
+
+static Eina_Bool video_to_primary = EINA_FALSE;
+static Eina_Bool video_punch = EINA_FALSE;
+
+EINTERN Eina_Bool
+e_video_debug_display_primary_plane_value_get(void)
+{
+ return video_to_primary;
+}
+
+EINTERN void
+e_video_debug_display_primary_plane_set(Eina_Bool set)
+{
+ video_to_primary = set;
+}
+
+EINTERN Eina_Bool
+e_video_debug_punch_value_get(void)
+{
+ return video_punch;
+}
+
+EINTERN void
+e_video_debug_punch_set(Eina_Bool set)
+{
+ video_punch = set;
+}
--- /dev/null
+#ifndef _E_VIDEO_DEBUG_H_
+#define _E_VIDEO_DEBUG_H_
+
+#include <Eina.h>
+
+EINTERN Eina_Bool e_video_debug_display_primary_plane_value_get(void);
+EINTERN void e_video_debug_display_primary_plane_set(Eina_Bool set);
+EINTERN Eina_Bool e_video_debug_punch_value_get(void);
+EINTERN void e_video_debug_punch_set(Eina_Bool set);
+
+#endif
--- /dev/null
+#ifndef _E_VIDEO_INTERNAL_H_
+#define _E_VIDEO_INTERNAL_H_
+
+#include "e.h"
+
+#include "e_video_debug.h"
+#include "e_zone_video.h"
+#include "e_comp_wl_video_buffer.h"
+
+#include <tdm.h>
+#include <values.h>
+#include <tdm_helper.h>
+#include <tbm_surface.h>
+#include <wayland-tbm-server.h>
+
+#ifdef VER
+# undef VER
+#endif
+
+#ifdef VWR
+# undef VWR
+#endif
+
+#ifdef VIN
+# undef VIN
+#endif
+
+#ifdef VDB
+# undef VDB
+#endif
+
+#ifdef DET
+# undef DET
+#endif
+
+#ifdef VDT
+# undef VDT
+#endif
+
+#define VER(fmt, arg...) ELOGF("VIDEO", "<ERR> window(0x%08"PRIxPTR"): "fmt, \
+ evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
+#define VWR(fmt, arg...) ELOGF("VIDEO", "<WRN> window(0x%08"PRIxPTR"): "fmt, \
+ evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
+#define VIN(fmt, arg...) ELOGF("VIDEO", "<INF> window(0x%08"PRIxPTR"): "fmt, \
+ evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
+#define VDB(fmt, arg...) DBG("window(0x%08"PRIxPTR") ec(%p): "fmt, evhp->window, evhp->ec, ##arg)
+
+#define GEO_FMT "%dx%d(%dx%d+%d+%d) -> (%dx%d+%d+%d) transform(%d)"
+#define GEO_ARG(g) \
+ (g)->input_w, (g)->input_h, \
+ (g)->input_r.w, (g)->input_r.h, (g)->input_r.x, (g)->input_r.y, \
+ (g)->output_r.w, (g)->output_r.h, (g)->output_r.x, (g)->output_r.y, \
+ (g)->transform
+
+typedef struct _E_Video_Comp_Iface E_Video_Comp_Iface;
+
+struct _E_Video_Comp_Iface
+{
+ void (*destroy)(E_Video_Comp_Iface *iface);
+ Eina_Bool (*follow_topmost_visibility)(E_Video_Comp_Iface *iface);
+ Eina_Bool (*unfollow_topmost_visibility)(E_Video_Comp_Iface *iface);
+ Eina_Bool (*allowed_property)(E_Video_Comp_Iface *iface);
+ Eina_Bool (*disallowed_property)(E_Video_Comp_Iface *iface);
+ Eina_Bool (*property_get)(E_Video_Comp_Iface *iface, unsigned int id, tdm_value *value);
+ Eina_Bool (*property_set)(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value);
+ Eina_Bool (*property_delay_set)(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value);
+ Eina_Bool (*available_properties_get)(E_Video_Comp_Iface *iface, const tdm_prop **props, int *count);
+ /* FIXME for hwc windows mode */
+ Eina_Bool (*info_get)(E_Video_Comp_Iface *iface, E_Client_Video_Info *info);
+ Eina_Bool (*commit_data_release)(E_Video_Comp_Iface *iface, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
+ tbm_surface_h (*tbm_surface_get)(E_Video_Comp_Iface *iface);
+};
+
+EINTERN E_Video_Comp_Iface *e_video_hwc_planes_iface_create(E_Client *ec);
+EINTERN E_Video_Comp_Iface *e_video_fallback_iface_create(E_Client *ec);
+
+#endif
--- /dev/null
+#include "e_video_internal.h"
+
+static int
+gcd(int a, int b)
+{
+ if (a % b == 0)
+ return b;
+ return gcd(b, a % b);
+}
+
+static int
+lcm(int a, int b)
+{
+ return a * b / gcd(a, b);
+}
+
+EINTERN Eina_Bool
+e_zone_video_available_size_get(E_Zone *zone, int *minw, int *minh, int *maxw, int *maxh, int *align)
+{
+ E_Output *output;
+ int ominw = -1, ominh = -1, omaxw = -1, omaxh = -1, oalign = -1;
+ int pminw = -1, pminh = -1, pmaxw = -1, pmaxh = -1, palign = -1;
+ int rminw = -1, rminh = -1, rmaxw = -1, rmaxh = -1, ralign = -1;
+
+ output = e_output_find(zone->output_id);
+
+ tdm_output_get_available_size(output->toutput, &ominw, &ominh, &omaxw, &omaxh, &oalign);
+ if (!e_comp_screen_pp_support())
+ {
+ rminw = ominw;
+ rminh = ominh;
+ rmaxw = omaxw;
+ rmaxh = omaxh;
+ ralign = oalign;
+
+ goto end;
+ }
+ else
+ {
+ tdm_display_get_pp_available_size(e_comp->e_comp_screen->tdisplay,
+ &pminw, &pminh, &pmaxw, &pmaxh,
+ &palign);
+
+ rminw = MAX(ominw, pminw);
+ rminh = MAX(ominh, pminh);
+
+ if (omaxw != -1 && pmaxw == -1)
+ rmaxw = omaxw;
+ else if (omaxw == -1 && pmaxw != -1)
+ rmaxw = pmaxw;
+ else
+ rmaxw = MIN(omaxw, pmaxw);
+
+ if (omaxh != -1 && pmaxh == -1)
+ rmaxh = omaxh;
+ else if (omaxh == -1 && pmaxh != -1)
+ rmaxh = pmaxh;
+ else
+ rmaxh = MIN(omaxh, pmaxh);
+
+ if (oalign != -1 && palign == -1)
+ ralign = oalign;
+ else if (oalign == -1 && palign != -1)
+ ralign = palign;
+ else if (oalign == -1 && palign == -1)
+ ralign = palign;
+ else if (oalign > 0 && palign > 0)
+ ralign = lcm(oalign, palign);
+ else
+ {
+ // ERR("invalid align: %d, %d", video->output_align, video->pp_align);
+ return EINA_FALSE;
+ }
+
+ /*
+ VIN("align width: output(%d) pp(%d) video(%d)",
+ video->output_align, video->pp_align, video->video_align);
+ */
+ }
+
+end:
+ if (minw) *minw = rminw;
+ if (minh) *minh = rminh;
+ if (maxw) *maxw = rmaxw;
+ if (maxw) *maxh = rmaxh;
+ if (align) *align = ralign;
+
+ return EINA_TRUE;
+}
--- /dev/null
+#ifndef _E_ZONE_VIDEO_H_
+#define _E_ZONE_VIDEO_H_
+
+EINTERN Eina_Bool e_zone_video_available_size_get(E_Zone *zone, int *minw, int *minh, int *maxw, int *maxh, int *align);
+
+#endif
--- /dev/null
+#include "../e_video_internal.h"
+
+typedef struct _E_Video_Fallback E_Video_Fallback;
+
+struct _E_Video_Fallback
+{
+ E_Video_Comp_Iface base;
+ E_Client *ec;
+};
+
+static void
+_e_video_fallback_iface_destroy(E_Video_Comp_Iface *iface)
+{
+ E_Video_Fallback *evs;
+
+ evs = container_of(iface, E_Video_Fallback, base);
+
+ /* Unset animatable lock */
+ e_policy_animatable_lock(evs->ec, E_POLICY_ANIMATABLE_NEVER, 0);
+
+ free(evs);
+}
+
+static void
+_e_video_fallback_init(E_Client *ec)
+{
+ /* software compositing */
+ ec->comp_data->video_client = 0;
+ /* Set animatable lock */
+ e_policy_animatable_lock(ec, E_POLICY_ANIMATABLE_NEVER, 1);
+}
+
+EINTERN E_Video_Comp_Iface *
+e_video_fallback_iface_create(E_Client *ec)
+{
+ E_Video_Fallback *evs;
+
+ INF("Intializing SW Compositing mode");
+
+ evs = E_NEW(E_Video_Fallback, 1);
+ if (!evs)
+ {
+ ERR("Failed to create E_Video_Fallback");
+ return NULL;
+ }
+
+ _e_video_fallback_init(ec);
+
+ evs->ec = ec;
+ evs->base.destroy = _e_video_fallback_iface_destroy;
+
+ return &evs->base;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../e_video_internal.h"
+
+//#define DUMP_BUFFER
+#define CHECKING_PRIMARY_ZPOS
+
+#define BUFFER_MAX_COUNT 5
+#define MIN_WIDTH 32
+
+#undef NEVER_GET_HERE
+#define NEVER_GET_HERE() CRI("** need to improve more **")
+
+#ifndef CLEAR
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+#endif
+
+#define IFACE_ENTRY \
+ E_Video_Hwc_Planes *evhp; \
+ evhp = container_of(iface, E_Video_Hwc_Planes, base)
+
+typedef struct _E_Video_Hwc_Planes E_Video_Hwc_Planes;
+typedef struct _E_Video_Layer E_Video_Layer;
+typedef struct _E_Video_Info_Layer E_Video_Info_Layer;
+
+/* the new TDM API doesn't have layers, so we have to invent layer here*/
+struct _E_Video_Layer
+{
+ E_Video_Hwc_Planes *evhp;
+
+ tdm_layer *tdm_layer;
+
+ /* for hwc_window */
+ E_Client_Video_Info info;
+ tbm_surface_h cur_tsurface; // tsurface to be set this layer.
+ E_Client *e_client;
+};
+
+struct _E_Video_Hwc_Planes
+{
+ E_Video_Comp_Iface base;
+
+ E_Client *ec;
+ Ecore_Window window;
+ tdm_output *output;
+ E_Output *e_output;
+ E_Video_Layer *layer;
+ E_Plane *e_plane;
+ Eina_Bool external_video;
+
+ Eina_List *ec_event_handler;
+
+ /* input info */
+ tbm_format tbmfmt;
+ Eina_List *input_buffer_list;
+
+ /* in screen coordinates */
+ struct
+ {
+ int input_w, input_h; /* input buffer's size */
+ Eina_Rectangle input_r; /* input buffer's content rect */
+ Eina_Rectangle output_r; /* video plane rect */
+ uint transform; /* rotate, flip */
+
+ Eina_Rectangle tdm_output_r; /* video plane rect in physical output coordinates */
+ uint tdm_transform; /* rotate, flip in physical output coordinates */
+ } geo, old_geo;
+
+ E_Comp_Wl_Buffer *old_comp_buffer;
+
+ /* converter info */
+ tbm_format pp_tbmfmt;
+ tdm_pp *pp;
+ Eina_Rectangle pp_r; /* converter dst content rect */
+ Eina_List *pp_buffer_list;
+ Eina_List *next_buffer;
+ Eina_Bool pp_scanout;
+
+ int pp_align;
+ int pp_minw, pp_minh, pp_maxw, pp_maxh;
+ int video_align;
+
+ /* When a video buffer be attached, it will be appended to the end of waiting_list .
+ * And when it's committed, it will be moved to committed_list.
+ * Finally when the commit handler is called, it will become current_fb.
+ */
+ Eina_List *waiting_list; /* buffers which are not committed yet */
+ Eina_List *committed_list; /* buffers which are committed, but not shown on screen yet */
+ E_Comp_Wl_Video_Buf *current_fb; /* buffer which is showing on screen currently */
+ Eina_Bool waiting_vblank;
+
+ /* attributes */
+ Eina_List *tdm_prop_list;
+ Eina_List *late_tdm_prop_list;
+ int tdm_mute_id;
+
+ Eina_Bool cb_registered;
+ Eina_Bool need_force_render;
+ Eina_Bool follow_topmost_visibility;
+ Eina_Bool allowed_attribute;
+
+ E_Plane_Hook *video_plane_ready_handler;
+};
+
+typedef struct _Tdm_Prop_Value
+{
+ unsigned int id;
+ char name[TDM_NAME_LEN];
+ tdm_value value;
+} Tdm_Prop_Value;
+
+static Eina_List *video_list = NULL;
+static Eina_List *video_layers = NULL;
+
+static Eina_Bool _e_video_set(E_Video_Hwc_Planes *evhp, E_Client *ec);
+static void _e_video_destroy(E_Video_Hwc_Planes *evhp);
+static void _e_video_render(E_Video_Hwc_Planes *evhp, const char *func);
+static Eina_Bool _e_video_frame_buffer_show(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Video_Buf *vbuf);
+static void _e_video_video_set_hook(void *data, E_Plane *plane);
+
+static tdm_layer* _e_video_tdm_video_layer_get(tdm_output *output);
+static tdm_layer* _e_video_tdm_available_video_layer_get(tdm_output *output);
+static void _e_video_tdm_set_layer_usable(tdm_layer *layer, Eina_Bool usable);
+static Eina_Bool _e_video_tdm_get_layer_usable(tdm_layer *layer);
+
+static void _e_video_vblank_handler(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+
+static void
+buffer_transform(int width, int height, uint32_t transform, int32_t scale,
+ int sx, int sy, int *dx, int *dy)
+{
+ switch (transform)
+ {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ default:
+ *dx = sx, *dy = sy;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ *dx = width - sx, *dy = sy;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ *dx = height - sy, *dy = sx;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ *dx = height - sy, *dy = width - sx;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ *dx = width - sx, *dy = height - sy;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ *dx = sx, *dy = height - sy;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ *dx = sy, *dy = width - sx;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ *dx = sy, *dy = sx;
+ break;
+ }
+
+ *dx *= scale;
+ *dy *= scale;
+}
+
+static E_Client *
+find_video_child_get(E_Client *ec)
+{
+ E_Client *subc = NULL;
+ Eina_List *l;
+ if (!ec) return NULL;
+ if (e_object_is_del(E_OBJECT(ec))) return NULL;
+ if (!ec->comp_data) return NULL;
+
+ if (ec->comp_data->video_client) return ec;
+
+ EINA_LIST_FOREACH(ec->comp_data->sub.below_list, l, subc)
+ {
+ E_Client *temp= NULL;
+ if (!subc->comp_data || e_object_is_del(E_OBJECT(subc))) continue;
+ temp = find_video_child_get(subc);
+ if(temp) return temp;
+ }
+
+ return NULL;
+}
+
+static E_Client *
+find_offscreen_parent_get(E_Client *ec)
+{
+ E_Client *parent = NULL;
+
+ if (!ec->comp_data || !ec->comp_data->sub.data)
+ return NULL;
+
+ parent = ec->comp_data->sub.data->parent;
+ while (parent)
+ {
+ if (!parent->comp_data || !parent->comp_data->sub.data)
+ return NULL;
+
+ if (parent->comp_data->sub.data->remote_surface.offscreen_parent)
+ return parent->comp_data->sub.data->remote_surface.offscreen_parent;
+
+ parent = parent->comp_data->sub.data->parent;
+ }
+
+ return NULL;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_vbuf_find(Eina_List *list, tbm_surface_h buffer)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l = NULL;
+
+ EINA_LIST_FOREACH(list, l, vbuf)
+ {
+ if (vbuf->tbm_surface == buffer)
+ return vbuf;
+ }
+
+ return NULL;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_vbuf_find_with_comp_buffer(Eina_List *list, E_Comp_Wl_Buffer *comp_buffer)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l = NULL;
+
+ EINA_LIST_FOREACH(list, l, vbuf)
+ {
+ if (vbuf->comp_buffer == comp_buffer)
+ return vbuf;
+ }
+
+ return NULL;
+}
+
+static E_Output *
+_get_e_output(tdm_output *output)
+{
+ Eina_List *l;
+ E_Output *eo;
+
+ EINA_LIST_FOREACH(e_comp->e_comp_screen->outputs, l, eo)
+ if (eo->toutput == output)
+ return eo;
+
+ return NULL;
+}
+
+static Eina_Bool
+_e_video_tdm_output_has_video_layer(tdm_output *toutput)
+{
+ E_Output *output = NULL;
+ tdm_layer *layer;
+ tdm_layer_capability lyr_capabilities = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(toutput, EINA_FALSE);
+
+ output = _get_e_output(toutput);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ /* get the first suitable layer */
+ layer = _e_video_tdm_video_layer_get(toutput);
+ if (!layer)
+ return EINA_FALSE;
+
+ tdm_layer_get_capabilities(layer, &lyr_capabilities);
+ if (lyr_capabilities & TDM_LAYER_CAPABILITY_VIDEO)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static E_Video_Layer *
+_e_video_available_video_layer_get(E_Video_Hwc_Planes *evhp)
+{
+ E_Video_Layer *layer = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp, NULL);
+
+ layer = calloc(1, sizeof(E_Video_Layer));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ layer->evhp = evhp;
+ layer->e_client = evhp->ec;
+
+
+ /* layer->tdm_layer = e_output_video_available_tdm_layer_get(evhp->e_output); */
+ layer->tdm_layer = _e_video_tdm_available_video_layer_get(evhp->output);
+ if (!layer->tdm_layer)
+ {
+ free(layer);
+ return NULL;
+ }
+ _e_video_tdm_set_layer_usable(layer->tdm_layer, EINA_FALSE);
+
+ return layer;
+}
+
+static tdm_error
+_e_video_layer_get_info(E_Video_Layer *layer, E_Client_Video_Info *vinfo)
+{
+ tdm_error ret = TDM_ERROR_NONE;
+ tdm_info_layer tinfo = {0};
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_INVALID_PARAMETER);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, TDM_ERROR_INVALID_PARAMETER);
+
+ ret = tdm_layer_get_info(layer->tdm_layer, &tinfo);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
+
+ memcpy(&vinfo->src_config, &tinfo.src_config, sizeof(tdm_info_config));
+ memcpy(&vinfo->dst_pos, &tinfo.dst_pos, sizeof(tdm_pos));
+ vinfo->transform = tinfo.transform;
+
+ return ret;
+}
+
+static tdm_error
+_e_video_layer_set_info(E_Video_Layer *layer, E_Client_Video_Info *vinfo)
+{
+ tdm_error ret = TDM_ERROR_NONE;
+ tdm_info_layer info_layer = {0};
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_INVALID_PARAMETER);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, TDM_ERROR_INVALID_PARAMETER);
+
+ memcpy(&info_layer.src_config, &vinfo->src_config, sizeof(tdm_info_config));
+ memcpy(&info_layer.dst_pos, &vinfo->dst_pos, sizeof(tdm_pos));
+ info_layer.transform = vinfo->transform;
+
+ ret = tdm_layer_set_info(layer->tdm_layer, &info_layer);
+
+ return ret;
+}
+
+static tdm_error
+_e_video_layer_set_buffer(E_Video_Layer * layer, tbm_surface_h buff)
+{
+ tdm_error ret = TDM_ERROR_NONE;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buff, TDM_ERROR_BAD_REQUEST);
+
+ ret = tdm_layer_set_buffer(layer->tdm_layer, buff);
+
+ return ret;
+}
+
+static tdm_error
+_e_video_layer_unset_buffer(E_Video_Layer *layer)
+{
+ tdm_error ret;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+
+ ret = tdm_layer_unset_buffer(layer->tdm_layer);
+
+ return ret;
+}
+
+/*
+ * This function checks if this layer was set
+ */
+static tdm_error
+_e_video_layer_is_usable(E_Video_Layer * layer, unsigned int *usable)
+{
+ tdm_error ret;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(usable, TDM_ERROR_BAD_REQUEST);
+
+ ret = tdm_layer_is_usable(layer->tdm_layer, usable);
+ return ret;
+}
+
+static tdm_error
+_e_video_layer_commit(E_Video_Layer *layer, tdm_layer_commit_handler func, void *user_data)
+{
+ tdm_error ret = TDM_ERROR_NONE;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+
+ ret = tdm_layer_commit(layer->tdm_layer, func, user_data);
+
+ return ret;
+}
+
+static tbm_surface_h
+_e_video_layer_get_displaying_buffer(E_Video_Layer *layer, int *tdm_error)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ return tdm_layer_get_displaying_buffer(layer->tdm_layer, tdm_error);
+}
+
+static tdm_error
+_e_video_layer_set_property(E_Video_Layer * layer, Tdm_Prop_Value *prop)
+{
+ tdm_error ret;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+
+ ret = tdm_layer_set_property(layer->tdm_layer, prop->id, prop->value);
+ return ret;
+}
+
+static void
+_e_video_layer_destroy(E_Video_Layer *layer)
+{
+ EINA_SAFETY_ON_NULL_RETURN(layer);
+
+ if (layer->tdm_layer)
+ _e_video_tdm_set_layer_usable(layer->tdm_layer, EINA_TRUE);
+
+ free(layer);
+}
+
+static Eina_Bool
+_e_video_set_layer(E_Video_Hwc_Planes *evhp, Eina_Bool set)
+{
+ Eina_Bool need_wait;
+
+ if (!set)
+ {
+ unsigned int usable = 1;
+ if (!evhp->layer) return EINA_TRUE;
+
+ _e_video_layer_is_usable(evhp->layer, &usable);
+ if (!usable && !evhp->video_plane_ready_handler)
+ {
+ VIN("stop video");
+ _e_video_layer_unset_buffer(evhp->layer);
+ _e_video_layer_commit(evhp->layer, NULL, NULL);
+ }
+
+ VIN("release layer: %p", evhp->layer);
+ _e_video_layer_destroy(evhp->layer);
+ evhp->layer = NULL;
+ evhp->old_comp_buffer = NULL;
+
+ e_plane_video_set(evhp->e_plane, EINA_FALSE, NULL);
+ evhp->e_plane = NULL;
+
+ E_FREE_FUNC(evhp->video_plane_ready_handler, e_plane_hook_del);
+ }
+ else
+ {
+ int zpos;
+ tdm_error ret;
+
+ if (evhp->layer) return EINA_TRUE;
+
+ evhp->layer = _e_video_available_video_layer_get(evhp);
+ if (!evhp->layer)
+ {
+ VWR("no available layer for evhp");
+ return EINA_FALSE;
+ }
+
+
+ ret = tdm_layer_get_zpos(evhp->layer->tdm_layer, &zpos);
+ if (ret == TDM_ERROR_NONE)
+ evhp->e_plane = e_output_plane_get_by_zpos(evhp->e_output, zpos);
+
+ if (!evhp->e_plane)
+ {
+ VWR("fail get e_plane");
+ _e_video_layer_destroy(evhp->layer);
+ evhp->layer = NULL;
+ return EINA_FALSE;
+ }
+
+ if (!e_plane_video_set(evhp->e_plane, EINA_TRUE, &need_wait))
+ {
+ VWR("fail set video to e_plane");
+ _e_video_layer_destroy(evhp->layer);
+ evhp->layer = NULL;
+ evhp->e_plane = NULL;
+ return EINA_FALSE;
+ }
+ if (need_wait)
+ {
+ evhp->video_plane_ready_handler =
+ e_plane_hook_add(E_PLANE_HOOK_VIDEO_SET,
+ _e_video_video_set_hook, evhp);
+ }
+
+ VIN("assign layer: %p", evhp->layer);
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_is_visible(E_Video_Hwc_Planes *evhp)
+{
+ E_Client *offscreen_parent;
+
+ if (e_object_is_del(E_OBJECT(evhp->ec))) return EINA_FALSE;
+
+ if (!e_pixmap_resource_get(evhp->ec->pixmap))
+ {
+ VDB("no comp buffer");
+ return EINA_FALSE;
+ }
+
+ if (evhp->ec->comp_data->sub.data && evhp->ec->comp_data->sub.data->stand_alone)
+ return EINA_TRUE;
+
+ offscreen_parent = find_offscreen_parent_get(evhp->ec);
+ if (offscreen_parent && offscreen_parent->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED)
+ {
+ VDB("video surface invisible: offscreen fully obscured");
+ return EINA_FALSE;
+ }
+
+ if (!evas_object_visible_get(evhp->ec->frame))
+ {
+ VDB("evas obj invisible");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_parent_is_viewable(E_Video_Hwc_Planes *evhp)
+{
+ E_Client *topmost_parent;
+
+ if (e_object_is_del(E_OBJECT(evhp->ec))) return EINA_FALSE;
+
+ topmost_parent = e_comp_wl_topmost_parent_get(evhp->ec);
+
+ if (!topmost_parent)
+ return EINA_FALSE;
+
+ if (topmost_parent == evhp->ec)
+ {
+ VDB("There is no video parent surface");
+ return EINA_FALSE;
+ }
+
+ if (!topmost_parent->visible)
+ {
+ VDB("parent(0x%08"PRIxPTR") not viewable", (Ecore_Window)e_client_util_win_get(topmost_parent));
+ return EINA_FALSE;
+ }
+
+ if (!e_pixmap_resource_get(topmost_parent->pixmap))
+ {
+ VDB("parent(0x%08"PRIxPTR") no comp buffer", (Ecore_Window)e_client_util_win_get(topmost_parent));
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_e_video_input_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
+{
+ E_Video_Hwc_Planes *evhp = data;
+ Eina_Bool need_hide = EINA_FALSE;
+
+ DBG("Buffer(%p) to be free, refcnt(%d)", vbuf, vbuf->ref_cnt);
+
+ evhp->input_buffer_list = eina_list_remove(evhp->input_buffer_list, vbuf);
+
+ if (vbuf->comp_buffer)
+ e_comp_wl_buffer_reference(&vbuf->buffer_ref, NULL);
+
+ if (evhp->current_fb == vbuf)
+ {
+ VIN("current fb destroyed");
+ e_comp_wl_video_buffer_set_use(evhp->current_fb, EINA_FALSE);
+ evhp->current_fb = NULL;
+ need_hide = EINA_TRUE;
+ }
+
+ if (eina_list_data_find(evhp->committed_list, vbuf))
+ {
+ VIN("committed fb destroyed");
+ evhp->committed_list = eina_list_remove(evhp->committed_list, vbuf);
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+ need_hide = EINA_TRUE;
+ }
+
+ if (eina_list_data_find(evhp->waiting_list, vbuf))
+ {
+ VIN("waiting fb destroyed");
+ evhp->waiting_list = eina_list_remove(evhp->waiting_list, vbuf);
+ }
+
+ if (need_hide && evhp->layer)
+ _e_video_frame_buffer_show(evhp, NULL);
+}
+
+static Eina_Bool
+_e_video_input_buffer_scanout_check(E_Comp_Wl_Video_Buf *vbuf)
+{
+ tbm_surface_h tbm_surface = NULL;
+ tbm_bo bo = NULL;
+ int flag;
+
+ tbm_surface = vbuf->tbm_surface;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, EINA_FALSE);
+
+ bo = tbm_surface_internal_get_bo(tbm_surface, 0);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(bo, EINA_FALSE);
+
+ flag = tbm_bo_get_flags(bo);
+ if (flag == TBM_BO_SCANOUT)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_input_buffer_copy(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Buffer *comp_buf, E_Comp_Wl_Video_Buf *vbuf, Eina_Bool scanout)
+{
+ E_Comp_Wl_Video_Buf *temp = NULL;
+ int aligned_width = ROUNDUP(vbuf->width_from_pitch, evhp->pp_align);
+
+ temp = e_comp_wl_video_buffer_alloc(aligned_width, vbuf->height, vbuf->tbmfmt, scanout);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(temp, NULL);
+
+ temp->comp_buffer = comp_buf;
+
+ VDB("copy vbuf(%d,%dx%d) => vbuf(%d,%dx%d)",
+ MSTAMP(vbuf), vbuf->width_from_pitch, vbuf->height,
+ MSTAMP(temp), temp->width_from_pitch, temp->height);
+
+ e_comp_wl_video_buffer_copy(vbuf, temp);
+ e_comp_wl_video_buffer_unref(vbuf);
+
+ evhp->geo.input_w = vbuf->width_from_pitch;
+#ifdef DUMP_BUFFER
+ char file[256];
+ static int i;
+ snprintf(file, sizeof file, "/tmp/dump/%s_%d.png", "cpy", i++);
+ tdm_helper_dump_buffer(temp->tbm_surface, file);
+#endif
+
+ return temp;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_input_buffer_get(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Buffer *comp_buffer, Eina_Bool scanout)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_Bool need_pp_scanout = EINA_FALSE;
+
+ vbuf = _e_video_vbuf_find_with_comp_buffer(evhp->input_buffer_list, comp_buffer);
+ if (vbuf)
+ {
+ vbuf->content_r = evhp->geo.input_r;
+ return vbuf;
+ }
+
+ vbuf = e_comp_wl_video_buffer_create_comp(comp_buffer);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+ if (evhp->pp_scanout)
+ {
+ Eina_Bool input_buffer_scanout = EINA_FALSE;
+ input_buffer_scanout = _e_video_input_buffer_scanout_check(vbuf);
+ if (!input_buffer_scanout) need_pp_scanout = EINA_TRUE;
+ }
+
+ if (evhp->pp)
+ {
+ if ((evhp->pp_align != -1 && (vbuf->width_from_pitch % evhp->pp_align)) ||
+ need_pp_scanout)
+ {
+ E_Comp_Wl_Video_Buf *temp;
+
+ if (need_pp_scanout)
+ temp = _e_video_input_buffer_copy(evhp, comp_buffer, vbuf, EINA_TRUE);
+ else
+ temp = _e_video_input_buffer_copy(evhp, comp_buffer, vbuf, scanout);
+ if (!temp)
+ {
+ e_comp_wl_video_buffer_unref(vbuf);
+ return NULL;
+ }
+ vbuf = temp;
+ }
+ }
+
+ vbuf->content_r = evhp->geo.input_r;
+
+ evhp->input_buffer_list = eina_list_append(evhp->input_buffer_list, vbuf);
+ e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_input_buffer_cb_free, evhp);
+
+ DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p) created, refcnt:%d"
+ " scanout=%d", e_client_util_name_get(evhp->ec) ?: "No Name" ,
+ evhp->ec->netwm.pid, wl_resource_get_id(evhp->ec->comp_data->surface), vbuf,
+ vbuf->ref_cnt, scanout);
+
+ return vbuf;
+}
+
+static void
+_e_video_input_buffer_valid(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Buffer *comp_buffer)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(evhp->input_buffer_list, l, vbuf)
+ {
+ tbm_surface_h tbm_surf;
+ tbm_bo bo;
+ uint32_t size = 0, offset = 0, pitch = 0;
+
+ if (!vbuf->comp_buffer) continue;
+ if (vbuf->resource == comp_buffer->resource)
+ {
+ WRN("got wl_buffer@%d twice", wl_resource_get_id(comp_buffer->resource));
+ return;
+ }
+
+ tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
+ bo = tbm_surface_internal_get_bo(tbm_surf, 0);
+ tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
+
+ if (vbuf->names[0] == tbm_bo_export(bo) && vbuf->offsets[0] == offset)
+ {
+ WRN("can tearing: wl_buffer@%d, wl_buffer@%d are same. gem_name(%d)",
+ wl_resource_get_id(vbuf->resource),
+ wl_resource_get_id(comp_buffer->resource), vbuf->names[0]);
+ return;
+ }
+ }
+}
+
+static void
+_e_video_pp_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
+{
+ E_Video_Hwc_Planes *evhp = data;
+
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+
+ if (evhp->current_fb == vbuf)
+ evhp->current_fb = NULL;
+
+ evhp->committed_list = eina_list_remove(evhp->committed_list, vbuf);
+
+ evhp->waiting_list = eina_list_remove(evhp->waiting_list, vbuf);
+
+ evhp->pp_buffer_list = eina_list_remove(evhp->pp_buffer_list, vbuf);
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_pp_buffer_get(E_Video_Hwc_Planes *evhp, int width, int height)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l;
+ int i = 0;
+ int aligned_width;
+
+ if (evhp->video_align != -1)
+ aligned_width = ROUNDUP(width, evhp->video_align);
+ else
+ aligned_width = width;
+
+ if (evhp->pp_buffer_list)
+ {
+ vbuf = eina_list_data_get(evhp->pp_buffer_list);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+ /* if we need bigger pp_buffers, destroy all pp_buffers and create */
+ if (aligned_width > vbuf->width_from_pitch || height != vbuf->height)
+ {
+ Eina_List *ll;
+
+ VIN("pp buffer changed: %dx%d => %dx%d",
+ vbuf->width_from_pitch, vbuf->height,
+ aligned_width, height);
+
+ EINA_LIST_FOREACH_SAFE(evhp->pp_buffer_list, l, ll, vbuf)
+ {
+ /* free forcely */
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+ e_comp_wl_video_buffer_unref(vbuf);
+ }
+ if (evhp->pp_buffer_list)
+ NEVER_GET_HERE();
+
+ if (evhp->waiting_list)
+ NEVER_GET_HERE();
+ }
+ }
+
+ if (!evhp->pp_buffer_list)
+ {
+ for (i = 0; i < BUFFER_MAX_COUNT; i++)
+ {
+ vbuf = e_comp_wl_video_buffer_alloc(aligned_width, height, evhp->pp_tbmfmt, EINA_TRUE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+ e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_pp_buffer_cb_free, evhp);
+ evhp->pp_buffer_list = eina_list_append(evhp->pp_buffer_list, vbuf);
+
+ }
+
+ VIN("pp buffer created: %dx%d, %c%c%c%c",
+ vbuf->width_from_pitch, height, FOURCC_STR(evhp->pp_tbmfmt));
+
+ evhp->next_buffer = evhp->pp_buffer_list;
+ }
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->pp_buffer_list, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->next_buffer, NULL);
+
+ l = evhp->next_buffer;
+ while ((vbuf = evhp->next_buffer->data))
+ {
+ evhp->next_buffer = (evhp->next_buffer->next) ? evhp->next_buffer->next : evhp->pp_buffer_list;
+
+ if (!vbuf->in_use)
+ return vbuf;
+
+ if (l == evhp->next_buffer)
+ {
+ VWR("all video framebuffers in use (max:%d)", BUFFER_MAX_COUNT);
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/* convert from logical screen to physical output */
+static void
+_e_video_geometry_cal_physical(E_Video_Hwc_Planes *evhp)
+{
+ E_Zone *zone;
+ E_Comp_Wl_Output *output;
+ E_Client *topmost;
+ int tran, flip;
+ int transform;
+
+ topmost = e_comp_wl_topmost_parent_get(evhp->ec);
+ EINA_SAFETY_ON_NULL_GOTO(topmost, normal);
+
+ output = e_comp_wl_output_find(topmost);
+ EINA_SAFETY_ON_NULL_GOTO(output, normal);
+
+ zone = e_comp_zone_xy_get(topmost->x, topmost->y);
+ EINA_SAFETY_ON_NULL_GOTO(zone, normal);
+
+ tran = evhp->geo.transform & 0x3;
+ flip = evhp->geo.transform & 0x4;
+ transform = flip + (tran + output->transform) % 4;
+ switch(transform)
+ {
+ case WL_OUTPUT_TRANSFORM_90:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_270;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_180;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_90;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_270;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_180;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_90;
+ break;
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ default:
+ evhp->geo.tdm_transform = TDM_TRANSFORM_NORMAL;
+ break;
+ }
+
+ if (output->transform % 2)
+ {
+ if (evhp->geo.tdm_transform == TDM_TRANSFORM_FLIPPED)
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_180;
+ else if (evhp->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_90)
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_270;
+ else if (evhp->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_180)
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED;
+ else if (evhp->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_270)
+ evhp->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_90;
+ }
+
+ if (output->transform == 0)
+ evhp->geo.tdm_output_r = evhp->geo.output_r;
+ else
+ e_comp_wl_rect_convert(zone->w, zone->h, output->transform, 1,
+ evhp->geo.output_r.x, evhp->geo.output_r.y,
+ evhp->geo.output_r.w, evhp->geo.output_r.h,
+ &evhp->geo.tdm_output_r.x, &evhp->geo.tdm_output_r.y,
+ &evhp->geo.tdm_output_r.w, &evhp->geo.tdm_output_r.h);
+
+ VDB("geomtry: screen(%d,%d %dx%d | %d) => %d => physical(%d,%d %dx%d | %d)",
+ EINA_RECTANGLE_ARGS(&evhp->geo.output_r), evhp->geo.transform, transform,
+ EINA_RECTANGLE_ARGS(&evhp->geo.tdm_output_r), evhp->geo.tdm_transform);
+
+ return;
+normal:
+ evhp->geo.tdm_output_r = evhp->geo.output_r;
+ evhp->geo.tdm_transform = evhp->geo.transform;
+}
+
+static Eina_Bool
+_e_video_geometry_cal_viewport(E_Video_Hwc_Planes *evhp)
+{
+ E_Client *ec = evhp->ec;
+ E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
+ E_Comp_Wl_Subsurf_Data *sdata;
+ int x1, y1, x2, y2;
+ int tx1, ty1, tx2, ty2;
+ E_Comp_Wl_Buffer *comp_buffer;
+ tbm_surface_h tbm_surf;
+ uint32_t size = 0, offset = 0, pitch = 0;
+ int bw, bh;
+ int width_from_buffer, height_from_buffer;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ comp_buffer = e_pixmap_resource_get(evhp->ec->pixmap);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(comp_buffer, EINA_FALSE);
+
+ tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surf, EINA_FALSE);
+
+ tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
+
+ /* input geometry */
+ if (IS_RGB(evhp->tbmfmt))
+ evhp->geo.input_w = pitch / 4;
+ else
+ evhp->geo.input_w = pitch;
+
+ evhp->geo.input_h = tbm_surface_get_height(tbm_surf);
+
+ bw = tbm_surface_get_width(tbm_surf);
+ bh = tbm_surface_get_height(tbm_surf);
+ VDB("TBM buffer size %d %d", bw, bh);
+
+ switch (vp->buffer.transform)
+ {
+ case WL_OUTPUT_TRANSFORM_90:
+ case WL_OUTPUT_TRANSFORM_270:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ width_from_buffer = bh / vp->buffer.scale;
+ height_from_buffer = bw / vp->buffer.scale;
+ break;
+ default:
+ width_from_buffer = bw / vp->buffer.scale;
+ height_from_buffer = bh / vp->buffer.scale;
+ break;
+ }
+
+
+ if (vp->buffer.src_width == wl_fixed_from_int(-1))
+ {
+ x1 = 0.0;
+ y1 = 0.0;
+ x2 = width_from_buffer;
+ y2 = height_from_buffer;
+ }
+ else
+ {
+ x1 = wl_fixed_to_int(vp->buffer.src_x);
+ y1 = wl_fixed_to_int(vp->buffer.src_y);
+ x2 = wl_fixed_to_int(vp->buffer.src_x + vp->buffer.src_width);
+ y2 = wl_fixed_to_int(vp->buffer.src_y + vp->buffer.src_height);
+ }
+
+ VDB("transform(%d) scale(%d) buffer(%dx%d) src(%d,%d %d,%d) viewport(%dx%d)",
+ vp->buffer.transform, vp->buffer.scale,
+ width_from_buffer, height_from_buffer,
+ x1, y1, x2 - x1, y2 - y1,
+ ec->comp_data->width_from_viewport, ec->comp_data->height_from_viewport);
+
+ buffer_transform(width_from_buffer, height_from_buffer,
+ vp->buffer.transform, vp->buffer.scale, x1, y1, &tx1, &ty1);
+ buffer_transform(width_from_buffer, height_from_buffer,
+ vp->buffer.transform, vp->buffer.scale, x2, y2, &tx2, &ty2);
+
+ evhp->geo.input_r.x = (tx1 <= tx2) ? tx1 : tx2;
+ evhp->geo.input_r.y = (ty1 <= ty2) ? ty1 : ty2;
+ evhp->geo.input_r.w = (tx1 <= tx2) ? tx2 - tx1 : tx1 - tx2;
+ evhp->geo.input_r.h = (ty1 <= ty2) ? ty2 - ty1 : ty1 - ty2;
+
+ /* output geometry */
+ if ((sdata = ec->comp_data->sub.data))
+ {
+ if (sdata->parent)
+ {
+ evhp->geo.output_r.x = sdata->parent->x + sdata->position.x;
+ evhp->geo.output_r.y = sdata->parent->y + sdata->position.y;
+ }
+ else
+ {
+ evhp->geo.output_r.x = sdata->position.x;
+ evhp->geo.output_r.y = sdata->position.y;
+ }
+ }
+ else
+ {
+ evhp->geo.output_r.x = ec->x;
+ evhp->geo.output_r.y = ec->y;
+ }
+
+ evhp->geo.output_r.w = ec->comp_data->width_from_viewport;
+ evhp->geo.output_r.w = (evhp->geo.output_r.w + 1) & ~1;
+ evhp->geo.output_r.h = ec->comp_data->height_from_viewport;
+
+ e_comp_object_frame_xy_unadjust(ec->frame,
+ evhp->geo.output_r.x, evhp->geo.output_r.y,
+ &evhp->geo.output_r.x, &evhp->geo.output_r.y);
+ e_comp_object_frame_wh_unadjust(ec->frame,
+ evhp->geo.output_r.w, evhp->geo.output_r.h,
+ &evhp->geo.output_r.w, &evhp->geo.output_r.h);
+
+ evhp->geo.transform = vp->buffer.transform;
+
+ _e_video_geometry_cal_physical(evhp);
+
+ VDB("geometry(%dx%d %d,%d %dx%d %d,%d %dx%d %d)",
+ evhp->geo.input_w, evhp->geo.input_h,
+ EINA_RECTANGLE_ARGS(&evhp->geo.input_r),
+ EINA_RECTANGLE_ARGS(&evhp->geo.output_r),
+ evhp->geo.transform);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_geometry_cal_map(E_Video_Hwc_Planes *evhp)
+{
+ E_Client *ec;
+ const Evas_Map *m;
+ Evas_Coord x1, x2, y1, y2;
+ Eina_Rectangle output_r;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp, EINA_FALSE);
+
+ ec = evhp->ec;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
+
+ m = evas_object_map_get(ec->frame);
+ if (!m) return EINA_TRUE;
+
+ /* If frame has map, it means that ec's geometry is decided by map's geometry.
+ * ec->x,y,w,h and ec->client.x,y,w,h is not useful.
+ */
+
+ evas_map_point_coord_get(m, 0, &x1, &y1, NULL);
+ evas_map_point_coord_get(m, 2, &x2, &y2, NULL);
+
+ output_r.x = x1;
+ output_r.y = y1;
+ output_r.w = x2 - x1;
+ output_r.w = (output_r.w + 1) & ~1;
+ output_r.h = y2 - y1;
+ output_r.h = (output_r.h + 1) & ~1;
+
+ if (!memcmp(&evhp->geo.output_r, &output_r, sizeof(Eina_Rectangle)))
+ return EINA_FALSE;
+
+ VDB("frame(%p) m(%p) output(%d,%d %dx%d) => (%d,%d %dx%d)", ec->frame, m,
+ EINA_RECTANGLE_ARGS(&evhp->geo.output_r), EINA_RECTANGLE_ARGS(&output_r));
+
+ evhp->geo.output_r = output_r;
+
+ _e_video_geometry_cal_physical(evhp);
+
+ return EINA_TRUE;
+}
+
+static void
+_e_video_geometry_cal_to_input(int output_w, int output_h, int input_w, int input_h,
+ uint32_t trasnform, int ox, int oy, int *ix, int *iy)
+{
+ float ratio_w, ratio_h;
+
+ switch(trasnform)
+ {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ default:
+ *ix = ox, *iy = oy;
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ *ix = oy, *iy = output_w - ox;
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ *ix = output_w - ox, *iy = output_h - oy;
+ break;
+ case WL_OUTPUT_TRANSFORM_90:
+ *ix = output_h - oy, *iy = ox;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ *ix = output_w - ox, *iy = oy;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ *ix = oy, *iy = ox;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ *ix = ox, *iy = output_h - oy;
+ break;
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ *ix = output_h - oy, *iy = output_w - ox;
+ break;
+ }
+ if (trasnform & 0x1)
+ {
+ ratio_w = (float)input_w / output_h;
+ ratio_h = (float)input_h / output_w;
+ }
+ else
+ {
+ ratio_w = (float)input_w / output_w;
+ ratio_h = (float)input_h / output_h;
+ }
+ *ix *= ratio_w;
+ *iy *= ratio_h;
+}
+
+static void
+_e_video_geometry_cal_to_input_rect(E_Video_Hwc_Planes * evhp, Eina_Rectangle *srect, Eina_Rectangle *drect)
+{
+ int xf1, yf1, xf2, yf2;
+
+ /* first transform box coordinates if the scaler is set */
+
+ xf1 = srect->x;
+ yf1 = srect->y;
+ xf2 = srect->x + srect->w;
+ yf2 = srect->y + srect->h;
+
+ _e_video_geometry_cal_to_input(evhp->geo.output_r.w, evhp->geo.output_r.h,
+ evhp->geo.input_r.w, evhp->geo.input_r.h,
+ evhp->geo.transform, xf1, yf1, &xf1, &yf1);
+ _e_video_geometry_cal_to_input(evhp->geo.output_r.w, evhp->geo.output_r.h,
+ evhp->geo.input_r.w, evhp->geo.input_r.h,
+ evhp->geo.transform, xf2, yf2, &xf2, &yf2);
+
+ drect->x = MIN(xf1, xf2);
+ drect->y = MIN(yf1, yf2);
+ drect->w = MAX(xf1, xf2) - drect->x;
+ drect->h = MAX(yf1, yf2) - drect->y;
+}
+
+static Eina_Bool
+_e_video_geometry_cal(E_Video_Hwc_Planes *evhp)
+{
+ Eina_Rectangle screen = {0,};
+ Eina_Rectangle output_r = {0,}, input_r = {0,};
+ const tdm_output_mode *mode = NULL;
+ tdm_error tdm_err = TDM_ERROR_NONE;
+
+ /* get geometry information with buffer scale, transform and viewport. */
+ if (!_e_video_geometry_cal_viewport(evhp))
+ return EINA_FALSE;
+
+ _e_video_geometry_cal_map(evhp);
+
+ if (e_config->eom_enable == EINA_TRUE && evhp->external_video)
+ {
+ tdm_err = tdm_output_get_mode(evhp->output, &mode);
+ if (tdm_err != TDM_ERROR_NONE)
+ return EINA_FALSE;
+
+ if (mode == NULL)
+ return EINA_FALSE;
+
+ screen.w = mode->hdisplay;
+ screen.h = mode->vdisplay;
+ }
+ else
+ {
+ E_Zone *zone;
+ E_Client *topmost;
+
+ topmost = e_comp_wl_topmost_parent_get(evhp->ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(topmost, EINA_FALSE);
+
+ zone = e_comp_zone_xy_get(topmost->x, topmost->y);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
+
+ screen.w = zone->w;
+ screen.h = zone->h;
+ }
+
+ e_comp_wl_video_buffer_size_get(evhp->ec, &input_r.w, &input_r.h);
+ // when topmost is not mapped, input size can be abnormal.
+ // in this case, it will be render by topmost showing.
+ if (!eina_rectangle_intersection(&evhp->geo.input_r, &input_r) || (evhp->geo.input_r.w <= 10 || evhp->geo.input_r.h <= 10))
+ {
+ VER("input area is empty");
+ return EINA_FALSE;
+ }
+
+ if (evhp->geo.output_r.x >= 0 && evhp->geo.output_r.y >= 0 &&
+ (evhp->geo.output_r.x + evhp->geo.output_r.w) <= screen.w &&
+ (evhp->geo.output_r.y + evhp->geo.output_r.h) <= screen.h)
+ return EINA_TRUE;
+
+ /* TODO: need to improve */
+
+ output_r = evhp->geo.output_r;
+ if (!eina_rectangle_intersection(&output_r, &screen))
+ {
+ VER("output_r(%d,%d %dx%d) screen(%d,%d %dx%d) => intersect(%d,%d %dx%d)",
+ EINA_RECTANGLE_ARGS(&evhp->geo.output_r),
+ EINA_RECTANGLE_ARGS(&screen), EINA_RECTANGLE_ARGS(&output_r));
+ return EINA_TRUE;
+ }
+
+ output_r.x -= evhp->geo.output_r.x;
+ output_r.y -= evhp->geo.output_r.y;
+
+ if (output_r.w <= 0 || output_r.h <= 0)
+ {
+ VER("output area is empty");
+ return EINA_FALSE;
+ }
+
+ VDB("output(%d,%d %dx%d) input(%d,%d %dx%d)",
+ EINA_RECTANGLE_ARGS(&output_r), EINA_RECTANGLE_ARGS(&input_r));
+
+ _e_video_geometry_cal_to_input_rect(evhp, &output_r, &input_r);
+
+ VDB("output(%d,%d %dx%d) input(%d,%d %dx%d)",
+ EINA_RECTANGLE_ARGS(&output_r), EINA_RECTANGLE_ARGS(&input_r));
+
+ output_r.x += evhp->geo.output_r.x;
+ output_r.y += evhp->geo.output_r.y;
+
+ input_r.x += evhp->geo.input_r.x;
+ input_r.y += evhp->geo.input_r.y;
+
+ output_r.x = output_r.x & ~1;
+ output_r.w = (output_r.w + 1) & ~1;
+
+ input_r.x = input_r.x & ~1;
+ input_r.w = (input_r.w + 1) & ~1;
+
+ evhp->geo.output_r = output_r;
+ evhp->geo.input_r = input_r;
+
+ _e_video_geometry_cal_physical(evhp);
+
+ return EINA_TRUE;
+}
+
+static void
+_e_video_format_info_get(E_Video_Hwc_Planes *evhp)
+{
+ E_Comp_Wl_Buffer *comp_buffer;
+ tbm_surface_h tbm_surf;
+
+ comp_buffer = e_pixmap_resource_get(evhp->ec->pixmap);
+ EINA_SAFETY_ON_NULL_RETURN(comp_buffer);
+
+ tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN(tbm_surf);
+
+ evhp->tbmfmt = tbm_surface_get_format(tbm_surf);
+}
+
+static Eina_Bool
+_e_video_can_commit(E_Video_Hwc_Planes *evhp)
+{
+ if (e_config->eom_enable == EINA_TRUE)
+ {
+ if (!evhp->external_video && e_output_dpms_get(evhp->e_output))
+ return EINA_FALSE;
+ }
+ else
+ if (e_output_dpms_get(evhp->e_output))
+ return EINA_FALSE;
+
+ if (!_e_video_is_visible(evhp))
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static void
+_e_video_commit_handler(tdm_layer *layer, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ E_Video_Hwc_Planes *evhp;
+ Eina_List *l;
+ E_Comp_Wl_Video_Buf *vbuf;
+
+ EINA_LIST_FOREACH(video_list, l, evhp)
+ {
+ if (evhp == user_data) break;
+ }
+
+ if (!evhp) return;
+ if (!evhp->committed_list) return;
+
+ if (_e_video_can_commit(evhp))
+ {
+ tbm_surface_h displaying_buffer = _e_video_layer_get_displaying_buffer(evhp->layer, NULL);
+
+ EINA_LIST_FOREACH(evhp->committed_list, l, vbuf)
+ {
+ if (vbuf->tbm_surface == displaying_buffer) break;
+ }
+ if (!vbuf) return;
+ }
+ else
+ vbuf = eina_list_nth(evhp->committed_list, 0);
+
+ evhp->committed_list = eina_list_remove(evhp->committed_list, vbuf);
+
+ /* client can attachs the same wl_buffer twice. */
+ if (evhp->current_fb && VBUF_IS_VALID(evhp->current_fb) && vbuf != evhp->current_fb)
+ {
+ e_comp_wl_video_buffer_set_use(evhp->current_fb, EINA_FALSE);
+
+ if (evhp->current_fb->comp_buffer)
+ e_comp_wl_buffer_reference(&evhp->current_fb->buffer_ref, NULL);
+ }
+
+ evhp->current_fb = vbuf;
+
+ VDB("current_fb(%d)", MSTAMP(evhp->current_fb));
+}
+
+static void
+_e_video_commit_buffer(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Video_Buf *vbuf)
+{
+ evhp->committed_list = eina_list_append(evhp->committed_list, vbuf);
+
+ if (!_e_video_can_commit(evhp))
+ goto no_commit;
+
+ if (!_e_video_frame_buffer_show(evhp, vbuf))
+ goto no_commit;
+
+ return;
+
+no_commit:
+ _e_video_commit_handler(NULL, 0, 0, 0, evhp);
+ _e_video_vblank_handler(NULL, 0, 0, 0, evhp);
+}
+
+static void
+_e_video_commit_from_waiting_list(E_Video_Hwc_Planes *evhp)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+
+ vbuf = eina_list_nth(evhp->waiting_list, 0);
+ evhp->waiting_list = eina_list_remove(evhp->waiting_list, vbuf);
+
+ _e_video_commit_buffer(evhp, vbuf);
+}
+
+static void
+_e_video_vblank_handler(tdm_output *output, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ E_Video_Hwc_Planes *evhp;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(video_list, l, evhp)
+ {
+ if (evhp == user_data) break;
+ }
+
+ if (!evhp) return;
+
+ evhp->waiting_vblank = EINA_FALSE;
+
+ if (evhp->video_plane_ready_handler) return;
+
+ if (evhp->waiting_list)
+ _e_video_commit_from_waiting_list(evhp);
+}
+
+static void
+_e_video_video_set_hook(void *data, E_Plane *plane)
+{
+ E_Video_Hwc_Planes *evhp = (E_Video_Hwc_Planes *)data;
+
+ if (evhp->e_plane != plane) return;
+ if (evhp->waiting_vblank) return;
+
+ if (evhp->waiting_list)
+ _e_video_commit_from_waiting_list(evhp);
+
+ E_FREE_FUNC(evhp->video_plane_ready_handler, e_plane_hook_del);
+}
+
+static Eina_Bool
+_e_video_frame_buffer_show(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Video_Buf *vbuf)
+{
+ E_Client_Video_Info info, old_info;
+ tdm_error ret;
+ E_Client *topmost;
+ Tdm_Prop_Value *prop;
+
+ if (!vbuf)
+ {
+ if (evhp->layer)
+ {
+ VIN("unset layer: hide");
+ _e_video_set_layer(evhp, EINA_FALSE);
+ }
+ return EINA_TRUE;
+ }
+
+ if (!evhp->layer)
+ {
+ VIN("set layer: show");
+ if (!_e_video_set_layer(evhp, EINA_TRUE))
+ {
+ VER("set layer failed");
+ return EINA_FALSE;
+ }
+ // need call tdm property in list
+ Tdm_Prop_Value *prop;
+ EINA_LIST_FREE(evhp->tdm_prop_list, prop)
+ {
+ VIN("call property(%s), value(%d)", prop->name, (unsigned int)prop->value.u32);
+ _e_video_layer_set_property(evhp->layer, prop);
+ free(prop);
+ }
+ }
+
+ CLEAR(old_info);
+ ret = _e_video_layer_get_info(evhp->layer, &old_info);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
+
+ CLEAR(info);
+ info.src_config.size.h = vbuf->width_from_pitch;
+ info.src_config.size.v = vbuf->height_from_size;
+ info.src_config.pos.x = vbuf->content_r.x;
+ info.src_config.pos.y = vbuf->content_r.y;
+ info.src_config.pos.w = vbuf->content_r.w;
+ info.src_config.pos.h = vbuf->content_r.h;
+ info.src_config.format = vbuf->tbmfmt;
+ info.dst_pos.x = evhp->geo.tdm_output_r.x;
+ info.dst_pos.y = evhp->geo.tdm_output_r.y;
+ info.dst_pos.w = evhp->geo.tdm_output_r.w;
+ info.dst_pos.h = evhp->geo.tdm_output_r.h;
+ info.transform = vbuf->content_t;
+
+ if (memcmp(&old_info, &info, sizeof(tdm_info_layer)))
+ {
+ ret = _e_video_layer_set_info(evhp->layer, &info);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
+ }
+
+ ret = _e_video_layer_set_buffer(evhp->layer, vbuf->tbm_surface);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
+
+ ret = _e_video_layer_commit(evhp->layer, _e_video_commit_handler, evhp);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
+
+ ret = tdm_output_wait_vblank(evhp->output, 1, 0, _e_video_vblank_handler, evhp);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
+
+ evhp->waiting_vblank = EINA_TRUE;
+
+ EINA_LIST_FREE(evhp->late_tdm_prop_list, prop)
+ {
+ VIN("call property(%s), value(%d)", prop->name, (unsigned int)prop->value.u32);
+ _e_video_layer_set_property(evhp->layer, prop);
+ free(prop);
+ }
+
+ topmost = e_comp_wl_topmost_parent_get(evhp->ec);
+ if (topmost && topmost->argb && !e_comp_object_mask_has(evhp->ec->frame))
+ {
+ Eina_Bool do_punch = EINA_TRUE;
+
+ /* FIXME: the mask obj can be drawn at the wrong position in the beginnig
+ * time. It happens caused by window manager policy.
+ */
+ if ((topmost->fullscreen || topmost->maximized) &&
+ (evhp->geo.output_r.x == 0 || evhp->geo.output_r.y == 0))
+ {
+ int bw, bh;
+
+ e_pixmap_size_get(topmost->pixmap, &bw, &bh);
+
+ if (bw > 100 && bh > 100 &&
+ evhp->geo.output_r.w < 100 && evhp->geo.output_r.h < 100)
+ {
+ VIN("don't punch. (%dx%d, %dx%d)",
+ bw, bh, evhp->geo.output_r.w, evhp->geo.output_r.h);
+ do_punch = EINA_FALSE;
+ }
+ }
+
+ if (do_punch)
+ {
+ e_comp_object_mask_set(evhp->ec->frame, EINA_TRUE);
+ VIN("punched");
+ }
+ }
+
+ if (e_video_debug_punch_value_get())
+ {
+ e_comp_object_mask_set(evhp->ec->frame, EINA_TRUE);
+ VIN("punched");
+ }
+
+ DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p, refcnt:%d) is shown."
+ "Geometry details are : buffer size(%dx%d) src(%d,%d, %dx%d)"
+ " dst(%d,%d, %dx%d), transform(%d)",
+ e_client_util_name_get(evhp->ec) ?: "No Name" , evhp->ec->netwm.pid,
+ wl_resource_get_id(evhp->ec->comp_data->surface), vbuf, vbuf->ref_cnt,
+ info.src_config.size.h, info.src_config.size.v, info.src_config.pos.x,
+ info.src_config.pos.y, info.src_config.pos.w, info.src_config.pos.h,
+ info.dst_pos.x, info.dst_pos.y, info.dst_pos.w, info.dst_pos.h, info.transform);
+
+
+ return EINA_TRUE;
+}
+
+static void
+_e_video_buffer_show(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Video_Buf *vbuf, unsigned int transform)
+{
+ vbuf->content_t = transform;
+
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_TRUE);
+
+ if (vbuf->comp_buffer)
+ e_comp_wl_buffer_reference(&vbuf->buffer_ref, vbuf->comp_buffer);
+
+ if (evhp->waiting_vblank || evhp->video_plane_ready_handler)
+ {
+ evhp->waiting_list = eina_list_append(evhp->waiting_list, vbuf);
+ VDB("There are waiting fbs more than 1");
+ return;
+ }
+
+ _e_video_commit_buffer(evhp, vbuf);
+}
+
+static void
+_e_video_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ E_Video_Hwc_Planes *evhp = data;
+
+ if (_e_video_geometry_cal_map(evhp))
+ _e_video_render(evhp, __FUNCTION__);
+}
+
+static void
+_e_video_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ E_Video_Hwc_Planes *evhp = data;
+
+ if (_e_video_geometry_cal_map(evhp))
+ _e_video_render(evhp, __FUNCTION__);
+}
+
+static void
+_e_video_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ E_Video_Hwc_Planes *evhp = data;
+
+ if (e_object_is_del(E_OBJECT(evhp->ec))) return;
+
+ if (!evhp->ec->comp_data->video_client)
+ return;
+
+ if (evhp->need_force_render)
+ {
+ VIN("video forcely rendering..");
+ _e_video_render(evhp, __FUNCTION__);
+ }
+
+ /* if stand_alone is true, not show */
+ if ((evhp->ec->comp_data->sub.data && evhp->ec->comp_data->sub.data->stand_alone) ||
+ (evhp->ec->comp_data->sub.data && evhp->follow_topmost_visibility))
+ {
+#if 0 //mute off is managed by client. mute off in server made many issues.
+ if (!evhp->layer) return;
+
+ if (evhp->tdm_mute_id != -1)
+ {
+ Tdm_Prop_Value prop = {.id = evhp->tdm_mute_id, .value.u32 = 0};
+ VIN("video surface show. mute off (ec:%p)", evhp->ec);
+ _e_video_layer_set_property(evhp->layer, &prop);
+ }
+#endif
+ return;
+ }
+
+ if (!evhp->layer)
+ {
+ VIN("set layer: show");
+ if (!_e_video_set_layer(evhp, EINA_TRUE))
+ {
+ VER("set layer failed");
+ return;
+ }
+ // need call tdm property in list
+ Tdm_Prop_Value *prop;
+ EINA_LIST_FREE(evhp->tdm_prop_list, prop)
+ {
+ VIN("call property(%s), value(%d)", prop->name, (unsigned int)prop->value.u32);
+ _e_video_layer_set_property(evhp->layer, prop);
+ free(prop);
+ }
+ }
+
+ VIN("evas show (ec:%p)", evhp->ec);
+ if (evhp->current_fb)
+ _e_video_buffer_show(evhp, evhp->current_fb, evhp->current_fb->content_t);
+}
+
+static void
+_e_video_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ E_Video_Hwc_Planes *evhp = data;
+
+ if (e_object_is_del(E_OBJECT(evhp->ec))) return;
+
+ if (!evhp->ec->comp_data->video_client)
+ return;
+
+ /* if stand_alone is true, not hide */
+ if (evhp->ec->comp_data->sub.data && evhp->ec->comp_data->sub.data->stand_alone)
+ {
+ if (!evhp->layer) return;
+
+ if (evhp->tdm_mute_id != -1)
+ {
+ Tdm_Prop_Value prop = {.id = evhp->tdm_mute_id, .value.u32 = 1};
+ VIN("video surface hide. mute on (ec:%p)", evhp->ec);
+ _e_video_layer_set_property(evhp->layer, &prop);
+ }
+ return;
+ }
+
+ VIN("evas hide (ec:%p)", evhp->ec);
+ _e_video_frame_buffer_show(evhp, NULL);
+}
+
+static E_Video_Hwc_Planes *
+_e_video_create(E_Client *ec)
+{
+ E_Video_Hwc_Planes *evhp;
+
+ evhp = calloc(1, sizeof *evhp);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp, NULL);
+
+ evhp->ec = ec;
+ evhp->pp_align = -1;
+ evhp->video_align = -1;
+ evhp->tdm_mute_id = -1;
+
+ if (!_e_video_set(evhp, ec))
+ {
+ free(evhp);
+ return NULL;
+ }
+
+ VIN("create. ec(%p) wl_surface@%d", ec, wl_resource_get_id(evhp->ec->comp_data->surface));
+
+ video_list = eina_list_append(video_list, evhp);
+
+ return evhp;
+}
+
+static tdm_error
+_e_video_layer_get_available_properties(E_Video_Layer *layer,
+ const tdm_prop **props,
+ int *count)
+{
+ tdm_error ret = TDM_ERROR_OPERATION_FAILED;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(props, TDM_ERROR_BAD_REQUEST);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(count, TDM_ERROR_BAD_REQUEST);
+
+ tdm_layer *tlayer = layer->tdm_layer;
+ /* if layer wasn't set then get an any available tdm_layer */
+ if (tlayer == NULL)
+ {
+
+ /* tlayer = e_output_video_available_tdm_layer_get(evhp->e_output); */
+ tlayer = _e_video_tdm_available_video_layer_get(layer->evhp->output);
+ }
+ ret = tdm_layer_get_available_properties(tlayer, props, count);
+
+ return ret;
+}
+
+static tdm_error
+_e_video_layer_get_property(E_Video_Layer * layer, unsigned id, tdm_value *value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, TDM_ERROR_BAD_REQUEST);
+
+ return tdm_layer_get_property(layer->tdm_layer, id, value);
+}
+
+static Eina_Bool
+_e_video_set(E_Video_Hwc_Planes *evhp, E_Client *ec)
+{
+ const tdm_prop *props;
+ int i, count = 0;
+
+ evhp->ec = ec;
+ evhp->window = e_client_util_win_get(ec);
+
+ if (e_config->eom_enable == EINA_TRUE)
+ {
+ evhp->external_video = e_eom_is_ec_external(ec);
+ if (evhp->external_video)
+ {
+ tdm_error ret;
+ unsigned int index = 0;
+
+ evhp->output = e_eom_tdm_output_by_ec_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->output, EINA_FALSE);
+
+ ret = tdm_output_get_pipe(evhp->output, &index);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
+
+ evhp->e_output = e_output_find_by_index(index);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->e_output, EINA_FALSE);
+
+ ec->comp_data->video_client = 1;
+
+ return EINA_TRUE;
+ }
+ }
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->ec->zone, EINA_FALSE);
+
+ evhp->e_output = e_output_find(evhp->ec->zone->output_id);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->e_output, EINA_FALSE);
+
+ evhp->output = evhp->e_output->toutput;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(evhp->output, EINA_FALSE);
+
+ /* if (e_output_video_capability_get(evhp->e_output)) */
+ if (_e_video_tdm_output_has_video_layer(evhp->output))
+ {
+ /* If tdm offers video layers, we will assign a tdm layer when showing */
+ VIN("video client");
+ ec->comp_data->video_client = 1;
+ }
+ else if (_e_video_set_layer(evhp, EINA_TRUE))
+ {
+ /* If tdm doesn't offer video layers, we assign a tdm layer now. If failed,
+ * video will be displayed via the UI rendering path.
+ */
+ VIN("video client");
+ ec->comp_data->video_client = 1;
+ }
+ else
+ return EINA_FALSE;
+
+ e_zone_video_available_size_get(ec->zone, NULL, NULL, NULL, NULL, &evhp->video_align);
+
+ _e_video_layer_get_available_properties(evhp->layer, &props, &count);
+ for (i = 0; i < count; i++)
+ {
+ tdm_value value;
+
+ _e_video_layer_get_property(evhp->layer, props[i].id, &value);
+ if (!strncmp(props[i].name, "mute", TDM_NAME_LEN))
+ evhp->tdm_mute_id = props[i].id;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_e_video_hide(E_Video_Hwc_Planes *evhp)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+
+ if (evhp->current_fb || evhp->committed_list)
+ _e_video_frame_buffer_show(evhp, NULL);
+
+ if (evhp->current_fb)
+ {
+ e_comp_wl_video_buffer_set_use(evhp->current_fb, EINA_FALSE);
+ evhp->current_fb = NULL;
+ }
+
+ if (evhp->old_comp_buffer)
+ evhp->old_comp_buffer = NULL;
+
+ EINA_LIST_FREE(evhp->committed_list, vbuf)
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+
+ EINA_LIST_FREE(evhp->waiting_list, vbuf)
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+}
+
+static void
+_e_video_destroy(E_Video_Hwc_Planes *evhp)
+{
+ E_Comp_Wl_Video_Buf *vbuf;
+ Eina_List *l = NULL, *ll = NULL;
+
+ if (!evhp)
+ return;
+
+ VIN("destroy");
+
+ if (evhp->cb_registered)
+ {
+ evas_object_event_callback_del_full(evhp->ec->frame, EVAS_CALLBACK_RESIZE,
+ _e_video_cb_evas_resize, evhp);
+ evas_object_event_callback_del_full(evhp->ec->frame, EVAS_CALLBACK_MOVE,
+ _e_video_cb_evas_move, evhp);
+ }
+
+ _e_video_hide(evhp);
+
+ /* others */
+ EINA_LIST_FOREACH_SAFE(evhp->input_buffer_list, l, ll, vbuf)
+ {
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+ e_comp_wl_video_buffer_unref(vbuf);
+ }
+
+ EINA_LIST_FOREACH_SAFE(evhp->pp_buffer_list, l, ll, vbuf)
+ {
+ e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+ e_comp_wl_video_buffer_unref(vbuf);
+ }
+
+ if(evhp->tdm_prop_list)
+ {
+ Tdm_Prop_Value *tdm_prop;
+ EINA_LIST_FREE(evhp->tdm_prop_list, tdm_prop)
+ {
+ free(tdm_prop);
+ }
+ }
+ if(evhp->late_tdm_prop_list)
+ {
+ Tdm_Prop_Value *tdm_prop;
+ EINA_LIST_FREE(evhp->late_tdm_prop_list, tdm_prop)
+ {
+ free(tdm_prop);
+ }
+ }
+
+ if (evhp->input_buffer_list)
+ NEVER_GET_HERE();
+ if (evhp->pp_buffer_list)
+ NEVER_GET_HERE();
+ if (evhp->tdm_prop_list)
+ NEVER_GET_HERE();
+ if (evhp->late_tdm_prop_list)
+ NEVER_GET_HERE();
+
+ /* destroy converter second */
+ if (evhp->pp)
+ tdm_pp_destroy(evhp->pp);
+
+ if (evhp->layer)
+ {
+ VIN("unset layer: destroy");
+ _e_video_set_layer(evhp, EINA_FALSE);
+ }
+
+ video_list = eina_list_remove(video_list, evhp);
+
+ free(evhp);
+
+#if 0
+ if (e_comp_wl_video_buffer_list_length() > 0)
+ e_comp_wl_video_buffer_list_print(NULL);
+#endif
+}
+
+static Eina_Bool
+_e_video_check_if_pp_needed(E_Video_Hwc_Planes *evhp)
+{
+ int i, count = 0;
+ const tbm_format *formats;
+ Eina_Bool found = EINA_FALSE;
+ tdm_layer_capability capabilities = 0;
+
+
+ tdm_layer *layer = _e_video_tdm_video_layer_get(evhp->output);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+
+ /* don't need pp if a layer has TDM_LAYER_CAPABILITY_VIDEO capability*/
+ if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
+ return EINA_FALSE;
+
+ /* check formats */
+ tdm_layer_get_available_formats(layer, &formats, &count);
+ for (i = 0; i < count; i++)
+ if (formats[i] == evhp->tbmfmt)
+ {
+ found = EINA_TRUE;
+ break;
+ }
+
+ if (!found)
+ {
+ if (formats && count > 0)
+ evhp->pp_tbmfmt = formats[0];
+ else
+ {
+ WRN("No layer format information!!!");
+ evhp->pp_tbmfmt = TBM_FORMAT_ARGB8888;
+ }
+ return EINA_TRUE;
+ }
+
+ if (capabilities & TDM_LAYER_CAPABILITY_SCANOUT)
+ goto need_pp;
+
+ /* check size */
+ if (evhp->geo.input_r.w != evhp->geo.output_r.w || evhp->geo.input_r.h != evhp->geo.output_r.h)
+ if (!(capabilities & TDM_LAYER_CAPABILITY_SCALE))
+ goto need_pp;
+
+ /* check rotate */
+ if (evhp->geo.transform || e_comp->e_comp_screen->rotation > 0)
+ if (!(capabilities & TDM_LAYER_CAPABILITY_TRANSFORM))
+ goto need_pp;
+
+ return EINA_FALSE;
+
+need_pp:
+ evhp->pp_tbmfmt = evhp->tbmfmt;
+ return EINA_TRUE;
+}
+
+static void
+_e_video_pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
+{
+ E_Video_Hwc_Planes *evhp = (E_Video_Hwc_Planes*)user_data;
+ E_Comp_Wl_Video_Buf *input_buffer, *pp_buffer;
+
+ input_buffer = _e_video_vbuf_find(evhp->input_buffer_list, sb);
+ if (input_buffer)
+ e_comp_wl_video_buffer_unref(input_buffer);
+
+ pp_buffer = _e_video_vbuf_find(evhp->pp_buffer_list, db);
+ if (pp_buffer)
+ {
+ e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
+ if (!_e_video_is_visible(evhp)) return;
+
+ _e_video_buffer_show(evhp, pp_buffer, 0);
+ }
+ else
+ {
+ VER("There is no pp_buffer");
+ // there is no way to set in_use flag.
+ // This will cause issue when server get available pp_buffer.
+ }
+}
+
+static void
+_e_video_render(E_Video_Hwc_Planes *evhp, const char *func)
+{
+ E_Comp_Wl_Buffer *comp_buffer;
+ E_Comp_Wl_Video_Buf *pp_buffer = NULL;
+ E_Comp_Wl_Video_Buf *input_buffer = NULL;
+ E_Client *topmost;
+
+ EINA_SAFETY_ON_NULL_RETURN(evhp->ec);
+
+ /* buffer can be NULL when camera/video's mode changed. Do nothing and
+ * keep previous frame in this case.
+ */
+ if (!evhp->ec->pixmap)
+ return;
+
+ if (!_e_video_is_visible(evhp))
+ {
+ _e_video_hide(evhp);
+ return;
+ }
+
+ comp_buffer = e_pixmap_resource_get(evhp->ec->pixmap);
+ if (!comp_buffer) return;
+
+ _e_video_format_info_get(evhp);
+
+ /* not interested with other buffer type */
+ if (!wayland_tbm_server_get_surface(NULL, comp_buffer->resource))
+ return;
+
+ topmost = e_comp_wl_topmost_parent_get(evhp->ec);
+ EINA_SAFETY_ON_NULL_RETURN(topmost);
+
+ if(e_comp_wl_viewport_is_changed(topmost))
+ {
+ VIN("need update viewport: apply topmost");
+ e_comp_wl_viewport_apply(topmost);
+ }
+
+ if (!_e_video_geometry_cal(evhp))
+ {
+ if(!evhp->need_force_render && !_e_video_parent_is_viewable(evhp))
+ {
+ VIN("need force render");
+ evhp->need_force_render = EINA_TRUE;
+ }
+ return;
+ }
+
+ DBG("====================================== (%s)", func);
+ VDB("old: "GEO_FMT" buf(%p)", GEO_ARG(&evhp->old_geo), evhp->old_comp_buffer);
+ VDB("new: "GEO_FMT" buf(%p) %c%c%c%c", GEO_ARG(&evhp->geo), comp_buffer, FOURCC_STR(evhp->tbmfmt));
+
+ if (!memcmp(&evhp->old_geo, &evhp->geo, sizeof evhp->geo) &&
+ evhp->old_comp_buffer == comp_buffer)
+ return;
+
+ evhp->need_force_render = EINA_FALSE;
+
+ _e_video_input_buffer_valid(evhp, comp_buffer);
+
+ if (!_e_video_check_if_pp_needed(evhp))
+ {
+ /* 1. non converting case */
+ input_buffer = _e_video_input_buffer_get(evhp, comp_buffer, EINA_TRUE);
+ EINA_SAFETY_ON_NULL_GOTO(input_buffer, render_fail);
+
+ _e_video_buffer_show(evhp, input_buffer, evhp->geo.tdm_transform);
+
+ evhp->old_geo = evhp->geo;
+ evhp->old_comp_buffer = comp_buffer;
+
+ goto done;
+ }
+
+ /* 2. converting case */
+ if (!evhp->pp)
+ {
+ tdm_pp_capability pp_cap;
+ tdm_error error = TDM_ERROR_NONE;
+
+ evhp->pp = tdm_display_create_pp(e_comp->e_comp_screen->tdisplay, NULL);
+ EINA_SAFETY_ON_NULL_GOTO(evhp->pp, render_fail);
+
+ tdm_display_get_pp_available_size(e_comp->e_comp_screen->tdisplay, &evhp->pp_minw, &evhp->pp_minh,
+ &evhp->pp_maxw, &evhp->pp_maxh, &evhp->pp_align);
+
+ error = tdm_display_get_pp_capabilities(e_comp->e_comp_screen->tdisplay, &pp_cap);
+ if (error == TDM_ERROR_NONE)
+ {
+ if (pp_cap & TDM_PP_CAPABILITY_SCANOUT)
+ evhp->pp_scanout = EINA_TRUE;
+ }
+ }
+
+ if ((evhp->pp_minw > 0 && (evhp->geo.input_r.w < evhp->pp_minw || evhp->geo.tdm_output_r.w < evhp->pp_minw)) ||
+ (evhp->pp_minh > 0 && (evhp->geo.input_r.h < evhp->pp_minh || evhp->geo.tdm_output_r.h < evhp->pp_minh)) ||
+ (evhp->pp_maxw > 0 && (evhp->geo.input_r.w > evhp->pp_maxw || evhp->geo.tdm_output_r.w > evhp->pp_maxw)) ||
+ (evhp->pp_maxh > 0 && (evhp->geo.input_r.h > evhp->pp_maxh || evhp->geo.tdm_output_r.h > evhp->pp_maxh)))
+ {
+ INF("size(%dx%d, %dx%d) is out of PP range",
+ evhp->geo.input_r.w, evhp->geo.input_r.h, evhp->geo.tdm_output_r.w, evhp->geo.tdm_output_r.h);
+ goto done;
+ }
+
+ input_buffer = _e_video_input_buffer_get(evhp, comp_buffer, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_GOTO(input_buffer, render_fail);
+
+ pp_buffer = _e_video_pp_buffer_get(evhp, evhp->geo.tdm_output_r.w, evhp->geo.tdm_output_r.h);
+ EINA_SAFETY_ON_NULL_GOTO(pp_buffer, render_fail);
+
+ if (memcmp(&evhp->old_geo, &evhp->geo, sizeof evhp->geo))
+ {
+ tdm_info_pp info;
+
+ CLEAR(info);
+ info.src_config.size.h = input_buffer->width_from_pitch;
+ info.src_config.size.v = input_buffer->height_from_size;
+ info.src_config.pos.x = evhp->geo.input_r.x;
+ info.src_config.pos.y = evhp->geo.input_r.y;
+ info.src_config.pos.w = evhp->geo.input_r.w;
+ info.src_config.pos.h = evhp->geo.input_r.h;
+ info.src_config.format = evhp->tbmfmt;
+ info.dst_config.size.h = pp_buffer->width_from_pitch;
+ info.dst_config.size.v = pp_buffer->height_from_size;
+ info.dst_config.pos.w = evhp->geo.tdm_output_r.w;
+ info.dst_config.pos.h = evhp->geo.tdm_output_r.h;
+ info.dst_config.format = evhp->pp_tbmfmt;
+ info.transform = evhp->geo.tdm_transform;
+
+ if (tdm_pp_set_info(evhp->pp, &info))
+ {
+ VER("tdm_pp_set_info() failed");
+ goto render_fail;
+ }
+
+ if (tdm_pp_set_done_handler(evhp->pp, _e_video_pp_cb_done, evhp))
+ {
+ VER("tdm_pp_set_done_handler() failed");
+ goto render_fail;
+ }
+
+ CLEAR(evhp->pp_r);
+ evhp->pp_r.w = info.dst_config.pos.w;
+ evhp->pp_r.h = info.dst_config.pos.h;
+ }
+
+ pp_buffer->content_r = evhp->pp_r;
+
+ if (tdm_pp_attach(evhp->pp, input_buffer->tbm_surface, pp_buffer->tbm_surface))
+ {
+ VER("tdm_pp_attach() failed");
+ goto render_fail;
+ }
+
+ e_comp_wl_video_buffer_set_use(pp_buffer, EINA_TRUE);
+
+ e_comp_wl_buffer_reference(&input_buffer->buffer_ref, comp_buffer);
+
+ if (tdm_pp_commit(evhp->pp))
+ {
+ VER("tdm_pp_commit() failed");
+ e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
+ goto render_fail;
+ }
+
+ evhp->old_geo = evhp->geo;
+ evhp->old_comp_buffer = comp_buffer;
+
+ goto done;
+
+render_fail:
+ if (input_buffer)
+ e_comp_wl_video_buffer_unref(input_buffer);
+
+done:
+ if (!evhp->cb_registered)
+ {
+ evas_object_event_callback_add(evhp->ec->frame, EVAS_CALLBACK_RESIZE,
+ _e_video_cb_evas_resize, evhp);
+ evas_object_event_callback_add(evhp->ec->frame, EVAS_CALLBACK_MOVE,
+ _e_video_cb_evas_move, evhp);
+ evhp->cb_registered = EINA_TRUE;
+ }
+ DBG("======================================.");
+}
+
+static Eina_Bool
+_e_video_cb_ec_buffer_change(void *data, int type, void *event)
+{
+ E_Client *ec;
+ E_Event_Client *ev = event;
+ E_Video_Hwc_Planes *evhp;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+ evhp = data;
+ ec = ev->ec;
+
+ if (evhp->ec != ec)
+ return ECORE_CALLBACK_PASS_ON;
+
+ if (e_object_is_del(E_OBJECT(ec)))
+ return ECORE_CALLBACK_PASS_ON;
+
+ /* not interested with non video_surface, */
+ if (!evhp->ec->comp_data->video_client)
+ return ECORE_CALLBACK_PASS_ON;
+
+ if (e_config->eom_enable == EINA_TRUE)
+ {
+ /* skip external client buffer if its top parent is not current for eom anymore */
+ if (evhp->external_video && e_eom_is_ec_external(ec))
+ {
+ VWR("skip external buffer");
+ return ECORE_CALLBACK_PASS_ON;
+ }
+ }
+
+ _e_video_render(evhp, __FUNCTION__);
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_video_cb_ec_client_show(void *data, int type, void *event)
+{
+ E_Event_Client *ev = event;
+ E_Client *ec;
+ E_Client *video_ec = NULL;
+ E_Video_Hwc_Planes *evhp = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+ ec = ev->ec;
+ if (!ec->comp_data) return ECORE_CALLBACK_PASS_ON;
+
+ video_ec = find_video_child_get(ec);
+ if (!video_ec) return ECORE_CALLBACK_PASS_ON;
+
+ evhp = data;
+ if (!evhp) return ECORE_CALLBACK_PASS_ON;
+
+ VIN("client(0x%08"PRIxPTR") show: find video child(0x%08"PRIxPTR")", (Ecore_Window)e_client_util_win_get(ec), (Ecore_Window)e_client_util_win_get(video_ec));
+ if(evhp->old_comp_buffer)
+ {
+ VIN("video already rendering..");
+ return ECORE_CALLBACK_PASS_ON;
+ }
+
+ if (ec == e_comp_wl_topmost_parent_get(evhp->ec))
+ {
+ if (e_config->eom_enable == EINA_TRUE)
+ {
+ /* skip external client buffer if its top parent is not current for eom anymore */
+ if (evhp->external_video && e_eom_is_ec_external(ec))
+ {
+ VWR("skip external buffer");
+ return ECORE_CALLBACK_PASS_ON;
+ }
+ }
+
+ VIN("video need rendering..");
+ e_comp_wl_viewport_apply(ec);
+ _e_video_render(evhp, __FUNCTION__);
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_video_cb_ec_visibility_change(void *data, int type, void *event)
+{
+ E_Event_Remote_Surface_Provider *ev = event;
+ E_Client *ec = ev->ec;
+ E_Video_Hwc_Planes *evhp;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(video_list, l, evhp)
+ {
+ E_Client *offscreen_parent = find_offscreen_parent_get(evhp->ec);
+ if (!offscreen_parent) continue;
+ if (offscreen_parent != ec) continue;
+ switch (ec->visibility.obscured)
+ {
+ case E_VISIBILITY_FULLY_OBSCURED:
+ _e_video_cb_evas_hide(evhp, NULL, NULL, NULL);
+ break;
+ case E_VISIBILITY_UNOBSCURED:
+ _e_video_cb_evas_show(evhp, NULL, NULL, NULL);
+ break;
+ default:
+ VER("Not implemented");
+ return ECORE_CALLBACK_PASS_ON;
+ }
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_video_cb_topmost_ec_visibility_change(void *data, int type, void *event)
+{
+ E_Event_Client *ev = event;
+ E_Client *ec = ev->ec;
+ E_Video_Hwc_Planes *evhp;
+ Eina_List *l = NULL;
+
+ EINA_LIST_FOREACH(video_list, l, evhp)
+ {
+ E_Client *topmost = e_comp_wl_topmost_parent_get(evhp->ec);
+ if (!topmost) continue;
+ if (topmost == evhp->ec) continue;
+ if (topmost != ec) continue;
+ if (evhp->follow_topmost_visibility)
+ {
+ switch (ec->visibility.obscured)
+ {
+ case E_VISIBILITY_FULLY_OBSCURED:
+ VIN("follow_topmost_visibility: fully_obscured");
+ _e_video_cb_evas_hide(evhp, NULL, NULL, NULL);
+ break;
+ case E_VISIBILITY_UNOBSCURED:
+ VIN("follow_topmost_visibility: UNOBSCURED");
+ _e_video_cb_evas_show(evhp, NULL, NULL, NULL);
+ break;
+ default:
+ return ECORE_CALLBACK_PASS_ON;
+ }
+ }
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static tdm_layer *
+_e_video_tdm_video_layer_get(tdm_output *output)
+{
+ int i, count = 0;
+#ifdef CHECKING_PRIMARY_ZPOS
+ int primary_idx = 0, primary_zpos = 0;
+ tdm_layer *primary_layer;
+#endif
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+ tdm_output_get_layer_count(output, &count);
+ for (i = 0; i < count; i++)
+ {
+ tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+ tdm_layer_capability capabilities = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+ if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
+ return layer;
+ }
+
+#ifdef CHECKING_PRIMARY_ZPOS
+ tdm_output_get_primary_index(output, &primary_idx);
+ primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
+ tdm_layer_get_zpos(primary_layer, &primary_zpos);
+#endif
+
+ for (i = 0; i < count; i++)
+ {
+ tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+ tdm_layer_capability capabilities = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+ if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
+ {
+#ifdef CHECKING_PRIMARY_ZPOS
+ int zpos = 0;
+ tdm_layer_get_zpos(layer, &zpos);
+ if (zpos >= primary_zpos) continue;
+#endif
+ return layer;
+ }
+ }
+
+ return NULL;
+}
+
+static tdm_layer *
+_e_video_tdm_available_video_layer_get(tdm_output *output)
+{
+ Eina_Bool has_video_layer = EINA_FALSE;
+ int i, count = 0;
+#ifdef CHECKING_PRIMARY_ZPOS
+ int primary_idx = 0, primary_zpos = 0;
+ tdm_layer *primary_layer;
+#endif
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+ /* check video layers first */
+ tdm_output_get_layer_count(output, &count);
+ for (i = 0; i < count; i++)
+ {
+ tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+ tdm_layer_capability capabilities = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+ if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
+ {
+ has_video_layer = EINA_TRUE;
+ if (!_e_video_tdm_get_layer_usable(layer)) continue;
+ return layer;
+ }
+ }
+
+ /* if a output has video layers, it means that there is no available video layer for video */
+ if (has_video_layer)
+ return NULL;
+
+ /* check graphic layers second */
+#ifdef CHECKING_PRIMARY_ZPOS
+ tdm_output_get_primary_index(output, &primary_idx);
+ primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
+ tdm_layer_get_zpos(primary_layer, &primary_zpos);
+#endif
+
+ for (i = 0; i < count; i++)
+ {
+ tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+ tdm_layer_capability capabilities = 0;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+ tdm_layer_get_capabilities(layer, &capabilities);
+ if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
+ {
+#ifdef CHECKING_PRIMARY_ZPOS
+ int zpos = 0;
+ tdm_layer_get_zpos(layer, &zpos);
+ if (zpos >= primary_zpos) continue;
+#endif
+ if (!_e_video_tdm_get_layer_usable(layer)) continue;
+ return layer;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+_e_video_tdm_set_layer_usable(tdm_layer *layer, Eina_Bool usable)
+{
+ if (usable)
+ video_layers = eina_list_remove(video_layers, layer);
+ else
+ {
+ tdm_layer *used_layer;
+ Eina_List *l = NULL;
+ EINA_LIST_FOREACH(video_layers, l, used_layer)
+ if (used_layer == layer) return;
+ video_layers = eina_list_append(video_layers, layer);
+ }
+}
+
+static Eina_Bool
+_e_video_tdm_get_layer_usable(tdm_layer *layer)
+{
+ tdm_layer *used_layer;
+ Eina_List *l = NULL;
+ EINA_LIST_FOREACH(video_layers, l, used_layer)
+ if (used_layer == layer)
+ return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+static void
+_e_video_hwc_planes_ec_event_deinit(E_Video_Hwc_Planes *evhp)
+{
+ E_Client *ec;
+
+ ec = evhp->ec;
+
+ evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_SHOW,
+ _e_video_cb_evas_show, evhp);
+ evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_HIDE,
+ _e_video_cb_evas_hide, evhp);
+
+ E_FREE_LIST(evhp->ec_event_handler, ecore_event_handler_del);
+}
+
+const char *
+_e_video_hwc_planes_prop_name_get_by_id(E_Video_Hwc_Planes *evhp, unsigned int id)
+{
+ tdm_layer *layer;
+ const tdm_prop *props;
+ int i, count = 0;
+
+ layer = _e_video_tdm_video_layer_get(evhp->output);
+ tdm_layer_get_available_properties(layer, &props, &count);
+ for (i = 0; i < count; i++)
+ {
+ if (props[i].id == id)
+ {
+ VDB("check property(%s)", props[i].name);
+ return props[i].name;
+ }
+ }
+
+ return NULL;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_property_post_set(E_Video_Hwc_Planes *evhp,
+ unsigned int id,
+ const char *name,
+ tdm_value value)
+{
+ Tdm_Prop_Value *prop = NULL;
+ const Eina_List *l = NULL;
+
+ EINA_LIST_FOREACH(evhp->late_tdm_prop_list, l, prop)
+ {
+ if (!strncmp(name, prop->name, TDM_NAME_LEN))
+ {
+ prop->value.u32 = value.u32;
+ VDB("update property(%s) value(%d)", prop->name, value.u32);
+ return EINA_FALSE;
+ }
+ }
+
+ prop = calloc(1, sizeof(Tdm_Prop_Value));
+ if(!prop) return EINA_FALSE;
+
+ prop->value.u32 = value.u32;
+ prop->id = id;
+ memcpy(prop->name, name, sizeof(TDM_NAME_LEN));
+ VIN("Add property(%s) value(%d)", prop->name, value.u32);
+ evhp->late_tdm_prop_list = eina_list_append(evhp->late_tdm_prop_list, prop);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_property_pre_set(E_Video_Hwc_Planes *evhp,
+ unsigned int id,
+ const char *name,
+ tdm_value value)
+{
+ Tdm_Prop_Value *prop = NULL;
+ const Eina_List *l = NULL;
+
+ EINA_LIST_FOREACH(evhp->tdm_prop_list, l, prop)
+ {
+ if (!strncmp(name, prop->name, TDM_NAME_LEN))
+ {
+ VDB("find prop data(%s) update value(%d -> %d)",
+ prop->name, (unsigned int)prop->value.u32, (unsigned int)value.u32);
+ prop->value.u32 = value.u32;
+ return EINA_TRUE;
+ }
+ }
+ EINA_LIST_FOREACH(evhp->late_tdm_prop_list, l, prop)
+ {
+ if (!strncmp(name, prop->name, TDM_NAME_LEN))
+ {
+ VDB("find prop data(%s) update value(%d -> %d)",
+ prop->name, (unsigned int)prop->value.u32, (unsigned int)value.u32);
+ prop->value.u32 = value.u32;
+ return EINA_TRUE;
+ }
+ }
+
+ prop = calloc(1, sizeof(Tdm_Prop_Value));
+ if(!prop) return EINA_FALSE;
+ prop->value.u32 = value.u32;
+ prop->id = id;
+ memcpy(prop->name, name, sizeof(TDM_NAME_LEN));
+ VIN("Add property(%s) value(%d)", prop->name, value.u32);
+ evhp->tdm_prop_list = eina_list_append(evhp->tdm_prop_list, prop);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_property_save(E_Video_Hwc_Planes *evhp, unsigned int id, const char *name, tdm_value value)
+{
+ /* FIXME workaround
+ * if mute off, need to do it after buffer commit */
+ if ((id == evhp->tdm_mute_id) && value.u32 == 0)
+ return _e_video_hwc_planes_property_post_set(evhp, id, name, value);
+ else
+ return _e_video_hwc_planes_property_pre_set(evhp, id, name, value);
+}
+
+static void
+_e_video_hwc_planes_ec_event_init(E_Video_Hwc_Planes *evhp)
+{
+ E_Client *ec;
+
+ ec = evhp->ec;
+
+ evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW,
+ _e_video_cb_evas_show, evhp);
+ evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE,
+ _e_video_cb_evas_hide, evhp);
+
+ E_LIST_HANDLER_APPEND(evhp->ec_event_handler, E_EVENT_CLIENT_BUFFER_CHANGE,
+ _e_video_cb_ec_buffer_change, evhp);
+ E_LIST_HANDLER_APPEND(evhp->ec_event_handler, E_EVENT_CLIENT_SHOW,
+ _e_video_cb_ec_client_show, evhp);
+ E_LIST_HANDLER_APPEND(evhp->ec_event_handler, E_EVENT_REMOTE_SURFACE_PROVIDER_VISIBILITY_CHANGE,
+ _e_video_cb_ec_visibility_change, evhp);
+ E_LIST_HANDLER_APPEND(evhp->ec_event_handler, E_EVENT_CLIENT_VISIBILITY_CHANGE,
+ _e_video_cb_topmost_ec_visibility_change, evhp);
+}
+
+static void
+_e_video_hwc_planes_iface_destroy(E_Video_Comp_Iface *iface)
+{
+ IFACE_ENTRY;
+
+ _e_video_hwc_planes_ec_event_deinit(evhp);
+ _e_video_destroy(evhp);
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_follow_topmost_visibility(E_Video_Comp_Iface *iface)
+{
+ IFACE_ENTRY;
+
+ evhp->follow_topmost_visibility = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_unfollow_topmost_visibility(E_Video_Comp_Iface *iface)
+{
+ IFACE_ENTRY;
+
+ evhp->follow_topmost_visibility = EINA_FALSE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_allowed_property(E_Video_Comp_Iface *iface)
+{
+ IFACE_ENTRY;
+
+ evhp->allowed_attribute = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_disallowed_property(E_Video_Comp_Iface *iface)
+{
+ IFACE_ENTRY;
+
+ evhp->allowed_attribute = EINA_FALSE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_property_get(E_Video_Comp_Iface *iface, unsigned int id, tdm_value *value)
+{
+ tdm_error ret;
+
+ IFACE_ENTRY;
+
+ ret = _e_video_layer_get_property(evhp->layer, id, value);
+ if (ret != TDM_ERROR_NONE)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_property_set(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value)
+{
+ Tdm_Prop_Value prop;
+ const char *name;
+
+ IFACE_ENTRY;
+
+ VIN("set layer: set_attribute");
+
+ name = _e_video_hwc_planes_prop_name_get_by_id(evhp, id);
+
+ if (!evhp->layer)
+ {
+ /* FIXME
+ * Set property with assigning layer right away if allowed_attribute
+ * flag is set. The reason why we have to do like this isn't figured
+ * yet. It's for backward compatibility. */
+ if (evhp->allowed_attribute)
+ {
+ if (!_e_video_set_layer(evhp, EINA_TRUE))
+ {
+ VER("set layer failed");
+ return EINA_FALSE;
+ }
+ }
+ else
+ {
+ VIN("no layer: save property value");
+ if (!_e_video_hwc_planes_property_save(evhp, id, name, value))
+ {
+ VER("save property failed");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+ }
+ }
+
+ VIN("set layer: call property(%s), value(%d)", name, value.u32);
+
+ prop.id = id;
+ prop.value = value;
+ _e_video_layer_set_property(evhp->layer, &prop);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_property_delay_set(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value)
+{
+ const char *name;
+
+ IFACE_ENTRY;
+
+ name = _e_video_hwc_planes_prop_name_get_by_id(evhp, id);
+
+ _e_video_hwc_planes_property_post_set(evhp, id, name, value);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_available_properties_get(E_Video_Comp_Iface *iface, const tdm_prop **props, int *count)
+{
+ tdm_error ret;
+
+ IFACE_ENTRY;
+
+ ret = _e_video_layer_get_available_properties(evhp->layer, props, count);
+ if (ret != TDM_ERROR_NONE)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_info_get(E_Video_Comp_Iface *iface, E_Client_Video_Info *info)
+{
+ tdm_error ret;
+
+ IFACE_ENTRY;
+
+ ret = _e_video_layer_get_info(evhp->layer, info);
+ if (ret != TDM_ERROR_NONE)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_planes_iface_commit_data_release(E_Video_Comp_Iface *iface, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
+{
+ IFACE_ENTRY;
+
+ if (!evhp->layer)
+ return EINA_FALSE;
+
+ _e_video_commit_handler(NULL, sequence, tv_sec, tv_usec, evhp);
+
+ return EINA_TRUE;
+}
+
+static tbm_surface_h
+_e_video_hwc_planes_iface_tbm_surface_get(E_Video_Comp_Iface *iface)
+{
+ IFACE_ENTRY;
+
+ if (!evhp->layer)
+ return NULL;
+
+ return evhp->layer->cur_tsurface;
+}
+
+EINTERN E_Video_Comp_Iface *
+e_video_hwc_planes_iface_create(E_Client *ec)
+{
+ E_Video_Hwc_Planes *evhp;
+
+ INF("Initializing HWC Planes mode");
+
+ evhp = _e_video_create(ec);
+ if (!evhp)
+ {
+ ERR("Failed to create 'E_Video_Hwc_Planes'");
+ return NULL;
+ }
+
+ _e_video_hwc_planes_ec_event_init(evhp);
+
+ evhp->base.destroy = _e_video_hwc_planes_iface_destroy;
+ evhp->base.follow_topmost_visibility = _e_video_hwc_planes_iface_follow_topmost_visibility;
+ evhp->base.unfollow_topmost_visibility = _e_video_hwc_planes_iface_unfollow_topmost_visibility;
+ evhp->base.allowed_property = _e_video_hwc_planes_iface_allowed_property;
+ evhp->base.disallowed_property = _e_video_hwc_planes_iface_disallowed_property;
+ evhp->base.property_get = _e_video_hwc_planes_iface_property_get;
+ evhp->base.property_set = _e_video_hwc_planes_iface_property_set;
+ evhp->base.property_delay_set = _e_video_hwc_planes_iface_property_delay_set;
+ evhp->base.available_properties_get = _e_video_hwc_planes_iface_available_properties_get;
+ evhp->base.info_get = _e_video_hwc_planes_iface_info_get;
+ evhp->base.commit_data_release = _e_video_hwc_planes_iface_commit_data_release;
+ evhp->base.tbm_surface_get = _e_video_hwc_planes_iface_tbm_surface_get;
+
+ return &evhp->base;
+}