From 294484348e201b423cbb1ea3651baab8a50023bb Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Tue, 6 Aug 2019 13:07:01 +0900 Subject: [PATCH] e_eom: refactoring the eom and the external outputs E20 needs to redesign the code for the support of the multi-dipslay. Change-Id: I14ace20c2d0011d7acf3245e4bded46ab20cb6a5 --- src/bin/e_eom.c | 2614 +++++++++++------------------------------------ src/bin/e_eom.h | 6 +- src/bin/e_hwc.h | 4 +- src/bin/e_hwc_planes.c | 176 ++++ src/bin/e_hwc_planes.h | 5 + src/bin/e_hwc_windows.c | 462 +++++++-- src/bin/e_hwc_windows.h | 2 + src/bin/e_output.c | 701 ++++++++----- src/bin/e_output.h | 20 +- 9 files changed, 1658 insertions(+), 2332 deletions(-) diff --git a/src/bin/e_eom.c b/src/bin/e_eom.c index f7bb76f..9d4acaa 100644 --- a/src/bin/e_eom.c +++ b/src/bin/e_eom.c @@ -12,23 +12,12 @@ #include #endif -/* -#define EOM_DUMP_MIRROR_BUFFERS -#define EOM_DUMP_PRESENTATION_BUFFERS -*/ +static int eom_trace_debug = 0; #define ALEN(array) (sizeof(array) / sizeof(array)[0]) #define EOM_NUM_ATTR 3 -#define EOM_CONNECT_CHECK_TIMEOUT 10.0 -#define EOM_DELAY_CHECK_TIMEOUT 1.0 -#define EOM_DELAY_CONNECT_CHECK_TIMEOUT 3.0 - -#define TDM_CONNECTOR_NAME_LEN 32 - -#ifndef CLEAR -#define CLEAR(x) memset(&(x), 0, sizeof (x)) -#endif +#define EOM_CONNECT_CHECK_TIMEOUT 4.0 #define EOERR(f, output, x...) \ do \ @@ -54,97 +43,25 @@ } \ while (0) -typedef struct _E_Eom E_Eom, *E_EomPtr; -typedef struct _E_Eom_Out_Mode E_EomOutMode, *E_EomOutModePtr; -typedef struct _E_Eom_Output E_EomOutput, *E_EomOutputPtr; +typedef struct _E_Eom E_Eom, *E_EomPtr; typedef struct _E_Eom_Client E_EomClient, *E_EomClientPtr; +typedef struct _E_Eom_Output E_EomOutput, *E_EomOutputPtr; typedef struct _E_Eom_Comp_Object_Intercept_Hook_Data E_EomCompObjectInterceptHookData; -typedef struct _E_Eom_Output_Buffer E_EomOutputBuffer, *E_EomOutputBufferPtr; -typedef struct _E_Eom_Buffer E_EomBuffer, *E_EomBufferPtr; -typedef struct _E_Eom_Output_Pp E_EomOutputPp, *E_EomOutputPpPtr; -typedef struct _E_Eom_Pp_Data E_EomPpData, *E_EomPpDataPtr; -typedef void(*E_EomEndShowingEventPtr)(E_EomOutputPtr eom_output, tbm_surface_h srfc, void * user_data); - -typedef enum -{ - NONE, - MIRROR, - PRESENTATION, - WAIT_PRESENTATION, /* It is used for delayed runnig of Presentation mode */ -} E_EomOutputState; - -typedef enum -{ - ROTATE_NONE, - ROTATE_INIT, - ROTATE_PENDING, - ROTATE_CANCEL, - ROTATE_DONE -} E_EomOutputRotate; struct _E_Eom { struct wl_global *global; - tdm_display *dpy; - unsigned int eom_output_count; Eina_List *eom_outputs; Eina_List *clients; Eina_List *handlers; Eina_List *hooks; Eina_List *comp_object_intercept_hooks; - Eina_List *added_outputs; E_Output_Hook *output_connect_status_hook; E_Output_Hook *output_mode_changes_hook; E_Output_Hook *output_add_hook; E_Output_Hook *output_remove_hook; - - /* Internal output data */ - E_Output *output_primary; - char check_first_boot; - Ecore_Timer *timer; -}; - -struct _E_Eom_Output -{ - unsigned int id; - eom_output_type_e type; - eom_output_mode_e mode; - unsigned int width; - unsigned int height; - unsigned int phys_width; - unsigned int phys_height; - - const char *name; - - tdm_output *output; - tdm_layer *primary_layer; - tdm_layer *overlay_layer; - Eina_Bool need_overlay_pp; - - E_EomOutputState state; - Eina_Bool connection_status; - enum wl_eom_status connection; - eom_output_attribute_e attribute; - - /* pp overlay (presentation mode subsurface data) */ - E_EomOutputPpPtr pp_overlay; - Eina_Bool pp_overlay_converting; - Eina_Bool pp_overlay_deinit; - Eina_List *pending_overlay_buff; /* can be deleted any time */ - E_EomOutputBufferPtr wait_overlay_buff; /* wait end of commit, can't be deleted */ - E_EomOutputBufferPtr show_overlay_buff; /* current showed buffer, can be deleted only after commit event with different buff */ - Eina_List *pending_pp_overlay; - Eina_List *pp_overlay_data; - - /* If attribute has been set while external output is disconnected - * then show black screen and wait until EOM client start sending - * buffers. After expiring of the delay start mirroring */ - Ecore_Timer *delay_timer; - - E_Output *eout; - Eina_Bool added; }; struct _E_Eom_Client @@ -158,40 +75,23 @@ struct _E_Eom_Client E_Client *ec; }; -struct _E_Eom_Output_Buffer -{ - E_EomOutputPtr eom_output; - tbm_surface_h tbm_surface; - E_EomEndShowingEventPtr cb_func; - void *cb_user_data; -}; - -struct _E_Eom_Buffer +struct _E_Eom_Output { - E_Comp_Wl_Buffer *wl_buffer; - E_Comp_Wl_Buffer_Ref comp_wl_buffer_ref; - - /* double reference to avoid sigterm crash */ - E_Comp_Wl_Buffer_Ref comp_wl_buffer_ref_2; -}; + unsigned int id; + eom_output_type_e type; + eom_output_attribute_e attribute; + enum wl_eom_status connection; -struct _E_Eom_Output_Pp -{ - tdm_pp *pp; - tbm_surface_queue_h queue; - tdm_info_pp pp_info; -}; + E_Output *output; + Eina_Bool added; -struct _E_Eom_Pp_Data -{ - E_EomOutputPtr eom_output; - E_EomBufferPtr eom_buffer; - tbm_surface_h tsurface; + E_EomClientPtr eom_client; }; struct _E_Eom_Comp_Object_Intercept_Hook_Data { E_Client *ec; + E_EomOutput *eom_output; E_Comp_Object_Intercept_Hook *hook; }; @@ -218,99 +118,37 @@ static int eom_output_attributes[EOM_NUM_ATTR][EOM_NUM_ATTR] = }; static E_EomPtr g_eom = NULL; -static Eina_Bool eom_trace_debug = 0; - -static void _e_eom_presentation_pp_run(E_EomOutputPtr eom_output, tbm_surface_h src_surface, E_EomBufferPtr eom_buff); - -static E_EomOutputBufferPtr -_e_eom_output_buff_create(E_EomOutputPtr eom_output, tbm_surface_h tbm_surface, E_EomEndShowingEventPtr cb_func, void *cb_user_data) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, NULL); - E_EomOutputBufferPtr outbuff = E_NEW(E_EomOutputBuffer, 1); - EINA_SAFETY_ON_NULL_RETURN_VAL(outbuff, NULL); - - if (eom_trace_debug) - EOINF("Allocate output buffer:%p", eom_output->eout, outbuff); - - outbuff->eom_output = eom_output; - - tbm_surface_internal_ref(tbm_surface); - outbuff->tbm_surface = tbm_surface; - - outbuff->cb_func = cb_func; - outbuff->cb_user_data = cb_user_data; - - return outbuff; -} - -static void -_e_eom_output_buff_delete(E_EomOutputBufferPtr buff) -{ - if (buff) - { - tbm_surface_internal_unref(buff->tbm_surface); - if (buff->cb_func) - buff->cb_func(buff->eom_output, buff->tbm_surface, buff->cb_user_data); - E_FREE(buff); - } -} - -static E_EomBuffer * -_e_eom_buffer_create(E_EomOutputPtr eom_output, E_Comp_Wl_Buffer *wl_buffer) -{ - E_EomBuffer * eom_buffer = E_NEW(E_EomBuffer, 1); - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_buffer, NULL); - - eom_buffer->wl_buffer = wl_buffer; - - /* Forbid E sending 'wl_buffer_send_release' event to external clients */ - e_comp_wl_buffer_reference(&eom_buffer->comp_wl_buffer_ref, wl_buffer); - - /* double reference to avoid sigterm crash */ - e_comp_wl_buffer_reference(&eom_buffer->comp_wl_buffer_ref_2, wl_buffer); - - if (eom_trace_debug) - EOINF("E_EomBuffer:%p wl_buffer:%p busy:%d", eom_output->eout, eom_buffer, wl_buffer, wl_buffer->busy); - return eom_buffer; -} - -static void -_e_eom_buffer_destroy(E_EomOutputPtr eom_output, E_EomBuffer *eom_buffer) +static Eina_Bool +_e_eom_cb_comp_object_redirected(void *data, E_Client *ec) { - EINA_SAFETY_ON_NULL_RETURN(eom_buffer); + E_EomCompObjectInterceptHookData *hook_data; - if (eom_trace_debug) - EOINF("wl_buffer:%p busy:%d", eom_output->eout, eom_buffer->wl_buffer, eom_buffer->wl_buffer->busy); + EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_TRUE); - eom_buffer->wl_buffer = NULL; + hook_data = (E_EomCompObjectInterceptHookData* )data; - e_comp_wl_buffer_reference(&eom_buffer->comp_wl_buffer_ref, NULL); + if (!hook_data->ec || !hook_data->hook) + return EINA_TRUE; - /* double reference to avoid sigterm crash */ - e_comp_wl_buffer_reference(&eom_buffer->comp_wl_buffer_ref_2, NULL); + if (hook_data->ec != ec) + return EINA_TRUE; - E_FREE(eom_buffer); -} + /* Hide the window from Enlightenment main screen */ + e_client_redirected_set(ec, EINA_FALSE); -static inline eom_output_mode_e -_e_eom_output_state_get_mode(E_EomOutputPtr eom_output) -{ - if (eom_output == NULL) return EOM_OUTPUT_MODE_NONE; + EOINF("Redirect ec:%p, ec->frame:%p", hook_data->eom_output->output, ec, ec->frame); - return eom_output->mode; -} + e_comp_object_intercept_hook_del(hook_data->hook); + g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks, hook_data); -static inline void -_e_eom_output_state_set_mode(E_EomOutputPtr eom_output, eom_output_mode_e mode) -{ - if (eom_output == NULL) return; + free(hook_data); - eom_output->mode = mode; + return EINA_TRUE; } static inline eom_output_attribute_e -_e_eom_output_state_get_attribute(E_EomOutputPtr eom_output) +_e_eom_output_attribute_get(E_EomOutputPtr eom_output) { if (eom_output == NULL) return EOM_OUTPUT_ATTRIBUTE_NONE; @@ -318,7 +156,7 @@ _e_eom_output_state_get_attribute(E_EomOutputPtr eom_output) } static inline void -_e_eom_output_state_set_force_attribute(E_EomOutputPtr eom_output, eom_output_attribute_e attribute) +_e_eom_output_attribute_force_set(E_EomOutputPtr eom_output, eom_output_attribute_e attribute) { if (eom_output == NULL) return; @@ -326,7 +164,7 @@ _e_eom_output_state_set_force_attribute(E_EomOutputPtr eom_output, eom_output_at } static inline Eina_Bool -_e_eom_output_state_set_attribute(E_EomOutputPtr eom_output, eom_output_attribute_e attribute) +_e_eom_output_attribute_set(E_EomOutputPtr eom_output, eom_output_attribute_e attribute) { if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE || eom_output->attribute == EOM_OUTPUT_ATTRIBUTE_NONE) { @@ -343,11 +181,34 @@ _e_eom_output_state_set_attribute(E_EomOutputPtr eom_output, eom_output_attribut return EINA_FALSE; } +static eom_output_mode_e +_e_eom_output_mode_get(E_Output_Display_Mode display_mode) +{ + switch (display_mode) + { + case E_OUTPUT_DISPLAY_MODE_NONE: + return EOM_OUTPUT_MODE_NONE; + case E_OUTPUT_DISPLAY_MODE_MIRROR: + return EOM_OUTPUT_MODE_MIRROR; + case E_OUTPUT_DISPLAY_MODE_PRESENTATION: + return EOM_OUTPUT_MODE_PRESENTATION; + default: + break; + } + + return EOM_OUTPUT_MODE_NONE; +} + static void _e_eom_output_info_broadcast(E_EomOutputPtr eom_output, eom_output_attribute_state_e attribute_state) { E_EomClientPtr eom_client = NULL; Eina_List *l = NULL; + int w, h, pw, ph; + + /* get the output size */ + e_output_size_get(eom_output->output, &w, &h); + e_output_phys_size_get(eom_output->output, &pw, &ph); /* If there were previously connected clients to the output - notify them */ EINA_LIST_FOREACH(g_eom->clients, l, eom_client) @@ -356,25 +217,27 @@ _e_eom_output_info_broadcast(E_EomOutputPtr eom_output, eom_output_attribute_sta if (!eom_client->resource) continue; if (attribute_state == EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE) - EOINF("Send output connected notification to client: %p", eom_output->eout, eom_client); + EOINF("Send output connected notification to client: %p", eom_output->output, eom_client); if (attribute_state == EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE) - EOINF("Send output disconnected notification to client: %p", eom_output->eout, eom_client); - - if (eom_client->current) - wl_eom_send_output_info(eom_client->resource, eom_output->id, - eom_output->type, eom_output->mode, - eom_output->width, eom_output->height, - eom_output->phys_width, eom_output->phys_height, + EOINF("Send output disconnected notification to client: %p", eom_output->output, eom_client); + + if (eom_client->ec == e_output_presentation_ec_get(eom_output->output)) + wl_eom_send_output_info(eom_client->resource, + eom_output->id, + eom_output->type, + e_output_display_mode_get(eom_output->output), + w, h, pw, ph, eom_output->connection, 0, - _e_eom_output_state_get_attribute(eom_output), + _e_eom_output_attribute_get(eom_output), attribute_state, EOM_ERROR_NONE); else - wl_eom_send_output_info(eom_client->resource, eom_output->id, - eom_output->type, eom_output->mode, - eom_output->width, eom_output->height, - eom_output->phys_width, eom_output->phys_height, + wl_eom_send_output_info(eom_client->resource, + eom_output->id, + eom_output->type, + e_output_display_mode_get(eom_output->output), + w, h, pw, ph, eom_output->connection, 1, 0, 0, 0); } @@ -385,6 +248,7 @@ _e_eom_output_status_broadcast(E_EomOutputPtr eom_output, E_EomClientPtr except_ { E_EomClientPtr eom_client = NULL; Eina_List *l = NULL; + E_Output_Display_Mode display_mode; EINA_LIST_FOREACH(g_eom->clients, l, eom_client) { @@ -393,1940 +257,646 @@ _e_eom_output_status_broadcast(E_EomOutputPtr eom_output, E_EomClientPtr except_ if (eom_client == except_client) continue; wl_eom_send_output_attribute(eom_client->resource, eom_output->id, - _e_eom_output_state_get_attribute(eom_output), + _e_eom_output_attribute_get(eom_output), attribute_state, EOM_ERROR_NONE); - wl_eom_send_output_mode(eom_client->resource, eom_output->id, - _e_eom_output_state_get_mode(eom_output)); + display_mode = e_output_display_mode_get(eom_output->output); + wl_eom_send_output_mode(eom_client->resource, eom_output->id, _e_eom_output_mode_get(display_mode)); } } -static Eina_Bool -_e_eom_output_video_layer_find(E_EomOutputPtr eom_output, tbm_format format) +static E_EomOutputPtr +_e_eom_output_find(E_Output *output) { - tdm_layer *layer = NULL; - tdm_layer *tmp_overlay_layer = NULL; - tdm_error err = TDM_ERROR_NONE; - tdm_layer_capability capa; - int i, count, format_count; - int primary_index = 0; - const tbm_format *formats; - - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output->output, EINA_FALSE); - - if (eom_output->overlay_layer) - { - if (eom_output->need_overlay_pp) - return EINA_FALSE; - else - return EINA_TRUE; - } - - err = tdm_output_get_layer_count(eom_output->output, &count); - if (err != TDM_ERROR_NONE) - { - EOERR("tdm_output_get_layer_count fail(%d)", eom_output->eout, err); - return EINA_FALSE; - } + E_EomOutputPtr eom_output = NULL; + Eina_List *l; - for (i = 0; i < count; i++) + EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) { - layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err); - EINA_SAFETY_ON_FALSE_RETURN_VAL(err == TDM_ERROR_NONE, EINA_FALSE); - - err = tdm_layer_get_capabilities(layer, &capa); - EINA_SAFETY_ON_FALSE_RETURN_VAL(err == TDM_ERROR_NONE, EINA_FALSE); - - if (capa & TDM_LAYER_CAPABILITY_PRIMARY) - { - primary_index = i + 1; - continue; - } - - if (primary_index == i) - tmp_overlay_layer = layer; - - if (capa & TDM_LAYER_CAPABILITY_VIDEO) - { - eom_output->overlay_layer = layer; - break; - } + if (eom_output->output == output) + return eom_output; } - if (eom_output->overlay_layer) - return EINA_TRUE; + return NULL; +} - for (i = 0; i < count; i++) - { - layer = (tdm_layer *)tdm_output_get_layer(eom_output->output, i, &err); - EINA_SAFETY_ON_FALSE_RETURN_VAL(err == TDM_ERROR_NONE, EINA_FALSE); +static Eina_Bool +_e_eom_output_create(E_Output *output, Eina_Bool added) +{ + E_EomOutputPtr eom_output = NULL; - err = tdm_layer_get_capabilities(layer, &capa); - EINA_SAFETY_ON_FALSE_RETURN_VAL(err == TDM_ERROR_NONE, EINA_FALSE); + if (!g_eom) return EINA_TRUE; - if ((capa & TDM_LAYER_CAPABILITY_PRIMARY) || (capa & TDM_LAYER_CAPABILITY_CURSOR)) - continue; + eom_output = E_NEW(E_EomOutput, 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, EINA_FALSE); - if (capa & TDM_LAYER_CAPABILITY_SCALE) - { - format_count = 0; - err = tdm_layer_get_available_formats(layer, &formats, &format_count); - EINA_SAFETY_ON_FALSE_RETURN_VAL(err == TDM_ERROR_NONE, EINA_FALSE); + eom_output->id = output->index; + eom_output->connection = WL_EOM_STATUS_NONE; + eom_output->output = output; + eom_output->type = (eom_output_type_e)output->toutput_type; + eom_output->added = added; - for (i = 0; i < count; i++) - { - if (formats[i] == format) - { - eom_output->overlay_layer = layer; - break; - } - } - } - } - if (eom_output->overlay_layer) - return EINA_TRUE; + g_eom->eom_outputs = eina_list_append(g_eom->eom_outputs, eom_output); - eom_output->overlay_layer = tmp_overlay_layer; + EOINF("create (%d)output, type:%d, added:%d", eom_output->output, + eom_output->id, eom_output->type, eom_output->added); - return EINA_FALSE; + return EINA_TRUE; } static Eina_Bool -_e_eom_pp_init(E_EomOutputPtr eom_output) +_e_eom_output_destroy(E_Output *output) { - tdm_error err = TDM_ERROR_NONE; - E_EomOutputPpPtr eom_pp = NULL; - tdm_pp *pp = NULL; - tbm_surface_queue_h queue = NULL; + E_EomOutputPtr eom_output = NULL; - if (eom_output->pp_overlay != NULL) - return EINA_TRUE; + if (!g_eom) return EINA_TRUE; - eom_pp = E_NEW(E_EomOutputPp, 1); - if (!eom_pp) - return EINA_FALSE; + eom_output = _e_eom_output_find(output); + EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, EINA_FALSE); - pp = tdm_display_create_pp(g_eom->dpy, &err); - EINA_SAFETY_ON_FALSE_GOTO(err == TDM_ERROR_NONE, error); - /* TODO: Add support for other formats */ - queue = tbm_surface_queue_create(3, eom_output->width,eom_output->height, - TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); - EINA_SAFETY_ON_NULL_GOTO(queue, error); + EOINF("destroy (%d)output, type:%d, added:%d", eom_output->output, + eom_output->id, eom_output->type, eom_output->added); - eom_pp->pp = pp; - eom_pp->queue = queue; + g_eom->eom_outputs = eina_list_remove(g_eom->eom_outputs, eom_output); - eom_output->pp_overlay = eom_pp; + E_FREE(eom_output); return EINA_TRUE; +} -error: - if (pp) - tdm_pp_destroy(pp); +static E_EomOutputPtr +_e_eom_output_get_by_id(int id) +{ + E_EomOutputPtr eom_output; + Eina_List *l; - if (eom_pp) - E_FREE(eom_pp); + EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) + { + if (eom_output && eom_output->id == id) + return eom_output; + } - return EINA_FALSE; + return NULL; } -static void -_e_eom_pp_deinit(E_EomOutputPtr eom_output) +static E_EomOutputPtr +_e_eom_output_by_ec_child_get(E_Client *ec) { - E_EomOutputPpPtr eom_pp = NULL; + E_EomOutputPtr eom_output = NULL; + E_Client *parent_ec = NULL, *output_ec = NULL; + Eina_List *l; - eom_pp = eom_output->pp_overlay; + EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) + { + output_ec = e_output_presentation_ec_get(eom_output->output); + if (!output_ec) continue; - if (!eom_pp) - return; + if (output_ec == ec) return eom_output; - if (eom_pp->queue) - { - if (eom_trace_debug) - EOINF("flush and destroy queue", eom_output->eout); - tbm_surface_queue_flush(eom_pp->queue); - tbm_surface_queue_destroy(eom_pp->queue); - } + if (!ec->comp_data) continue; + if (!ec->comp_data->sub.data) continue; - if (eom_pp->pp) - tdm_pp_destroy(eom_pp->pp); + parent_ec = ec->comp_data->sub.data->parent; + while (parent_ec) + { + if (parent_ec == output_ec) return eom_output; + if (!parent_ec->comp_data) break; + if (!parent_ec->comp_data->sub.data) break; - E_FREE(eom_pp); + parent_ec = parent_ec->comp_data->sub.data->parent; + } + } - eom_output->pp_overlay = NULL; + return NULL; } static void -_e_eom_util_calculate_fullsize(int src_h, int src_v, int dst_size_h, int dst_size_v, - int *dst_x, int *dst_y, int *dst_w, int *dst_h) +_e_eom_output_send_configure_event(E_EomOutput *eom_output, E_Client *ec) { - double h_ratio, v_ratio; - - h_ratio = (double)src_h / (double)dst_size_h; - v_ratio = (double)src_v / (double)dst_size_v; + E_Comp_Client_Data *cdata = NULL; + E_EomCompObjectInterceptHookData *hook_data = NULL; + E_Comp_Object_Intercept_Hook *hook = NULL; + int w, h; - if (h_ratio == v_ratio) - { - *dst_x = 0; - *dst_y = 0; - *dst_w = dst_size_h; - *dst_h = dst_size_v; - } - else if (h_ratio < v_ratio) - { - *dst_y = 0; - *dst_h = dst_size_v; - *dst_w = dst_size_v * src_h / src_v; - *dst_x = (dst_size_h - *dst_w) / 2; - } - else /* (h_ratio > v_ratio) */ - { - *dst_x = 0; - *dst_w = dst_size_h; - *dst_h = dst_size_h * src_h / src_v; - *dst_y = (dst_size_v - *dst_h) / 2; - } -} + ec = e_output_presentation_ec_get(eom_output->output); + EINA_SAFETY_ON_NULL_RETURN(ec); -static void -_e_eom_tbm_buffer_release_pp_overlay(E_EomOutputPtr eom_output, tbm_surface_h surface, void *eom_buff) -{ - if (eom_trace_debug) - EOINF("release pp_overlay tbm_surface_h:%p data:%p", eom_output->eout, surface, eom_buff); + cdata = ec->comp_data; + EINA_SAFETY_ON_NULL_RETURN(cdata); + EINA_SAFETY_ON_NULL_RETURN(cdata->shell.configure_send); - if (!eom_output->pp_overlay || !eom_output->pp_overlay->queue) - return; + hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1); + EINA_SAFETY_ON_NULL_RETURN(hook_data); - tbm_surface_queue_release(eom_output->pp_overlay->queue, surface); + hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, + _e_eom_cb_comp_object_redirected, hook_data); + EINA_SAFETY_ON_NULL_GOTO(hook, err); - _e_eom_buffer_destroy(eom_output, eom_buff); -} + hook_data->ec = ec; + hook_data->eom_output = eom_output; + hook_data->hook = hook; -static void -_e_eom_cb_layer_commit(tdm_layer *layer EINA_UNUSED, unsigned int sequence EINA_UNUSED, - unsigned int tv_sec EINA_UNUSED, unsigned int tv_usec EINA_UNUSED, - void *user_data) -{ - E_EomOutputBufferPtr outbuff = NULL; - E_EomOutputPtr eom_output = NULL; - tdm_error err = TDM_ERROR_NONE; - E_EomOutputBufferPtr wait_buff; - E_EomOutputBufferPtr show_buff; - E_EomPpDataPtr pending_pp = NULL; - tdm_layer *tlayer; - tbm_surface_h tsurface; - E_EomBufferPtr eom_buffer; + g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks, hook_data); - EINA_SAFETY_ON_NULL_RETURN(user_data); - outbuff = (E_EomOutputBufferPtr)user_data; + /* get the output size */ + e_output_size_get(eom_output->output, &w, &h); + cdata->shell.configure_send(ec->comp_data->shell.surface, 0, w, h); - eom_output = outbuff->eom_output; - EINA_SAFETY_ON_NULL_RETURN(eom_output); + EOINF("Send Configure Event for Presentation (%d X %d)", eom_output->output, w, h); +err: + if (hook_data) + free(hook_data); +} - if (eom_trace_debug) - EOINF("========================> CM END tbm_buff:%p", eom_output->eout, outbuff->tbm_surface); +static E_EomClientPtr +_e_eom_client_get_by_resource(struct wl_resource *resource) +{ + Eina_List *l; + E_EomClientPtr client; - /*it means that eom_output has been canceled*/ - if (eom_output->wait_overlay_buff == NULL) + EINA_LIST_FOREACH(g_eom->clients, l, client) { - _e_eom_output_buff_delete(outbuff); - return; + if (client && client->resource == resource) + return client; } - wait_buff = eom_output->wait_overlay_buff; - show_buff = eom_output->show_overlay_buff; - tlayer = eom_output->overlay_layer; - EINA_SAFETY_ON_FALSE_RETURN(wait_buff == outbuff); + return NULL; +} - if (eom_trace_debug) - EOINF("commit finish tbm_surface_h:%p", eom_output->eout, outbuff->tbm_surface); +static E_EomClientPtr +_e_eom_client_get_current_by_ec(E_Client *ec) +{ + Eina_List *l; + E_EomClientPtr client; - /* check if show buffer is present */ - if (show_buff != NULL) + EINA_LIST_FOREACH(g_eom->clients, l, client) { - if (eom_trace_debug) - EOINF("delete show buffer tbm_surface_h:%p", eom_output->eout, show_buff->tbm_surface); - _e_eom_output_buff_delete(show_buff); - eom_output->show_overlay_buff = NULL; + if (client && client->current == EINA_TRUE && client->ec == ec) + return client; } - /* set wait_buffer as show_buff */ - if (eom_trace_debug) - EOINF("set wait_buffer as show_buff tbm_surface_h:%p", eom_output->eout, outbuff->tbm_surface); + return NULL; +} + +static E_EomClientPtr +_e_eom_client_get_current_by_ec_parrent(E_Client *ec) +{ + Eina_List *l; + E_EomClientPtr client; + E_Client *parent = NULL; - eom_output->wait_overlay_buff = NULL; - eom_output->show_overlay_buff = outbuff; + if (!ec->comp_data || !ec->comp_data->sub.data) + return NULL; - /* check if pending buffer is present */ - if (eina_list_count(eom_output->pending_overlay_buff) != 0) + EINA_LIST_FOREACH(g_eom->clients, l, client) { - outbuff = eina_list_nth(eom_output->pending_overlay_buff, 0); - if (outbuff != NULL) + parent = ec->comp_data->sub.data->parent; + while (parent) { - eom_output->pending_overlay_buff = eina_list_remove(eom_output->pending_overlay_buff, outbuff); - - if (eom_trace_debug) - { - EOINF("========================> CM- START tbm_buff:%p", eom_output->eout, outbuff->tbm_surface); - EOINF("do commit tdm_output:%p tdm_layer:%p tbm_surface_h:%p", eom_output->eout, - eom_output->output, tlayer, outbuff->tbm_surface); - } - err = tdm_layer_set_buffer(tlayer, outbuff->tbm_surface); - EINA_SAFETY_ON_FALSE_GOTO(err == TDM_ERROR_NONE, error); + if (client->ec == parent) + return client; - err = tdm_layer_commit(tlayer, _e_eom_cb_layer_commit, outbuff); - EINA_SAFETY_ON_FALSE_GOTO(err == TDM_ERROR_NONE, error2); + if (!parent->comp_data || !parent->comp_data->sub.data) + break; - eom_output->wait_overlay_buff = outbuff; + parent = parent->comp_data->sub.data->parent; } } - if (eina_list_count(eom_output->pending_pp_overlay) != 0) - { - pending_pp = eina_list_nth(eom_output->pending_pp_overlay, 0); - if (pending_pp != NULL) - { - if (!tbm_surface_queue_can_dequeue(eom_output->pp_overlay->queue, 0)) - return; - - eom_output->pending_pp_overlay = eina_list_remove(eom_output->pending_pp_overlay, pending_pp); - - tsurface = pending_pp->tsurface; - eom_buffer = pending_pp->eom_buffer; - - E_FREE(pending_pp); - - _e_eom_presentation_pp_run(eom_output, tsurface, eom_buffer); - } - } - - return; - -error2: - tdm_layer_unset_buffer(tlayer); - -error: - EOINF("========================> CM- ENDERR tbm_buff:%p", eom_output->eout, outbuff->tbm_surface); - - _e_eom_output_buff_delete(outbuff); + return NULL; } static Eina_Bool -_e_eom_output_show(E_EomOutputPtr eom_output, tbm_surface_h tbm_srfc, - E_EomEndShowingEventPtr cb_func, void *cb_user_data) +_e_eom_cb_client_buffer_change(void *data, int type, void *event) { - tdm_error err = TDM_ERROR_NONE; - tdm_layer *layer; - - /* create new output buffer */ - E_EomOutputBufferPtr outbuff = _e_eom_output_buff_create(eom_output, tbm_srfc, cb_func, cb_user_data); - EINA_SAFETY_ON_NULL_RETURN_VAL(outbuff, EINA_FALSE); + E_EomClientPtr eom_client = NULL, eom_client_itr = NULL; + E_EomOutputPtr eom_output = NULL; + E_Event_Client *ev = event; + E_Client *ec = NULL; + E_Comp_Wl_Buffer *wl_buffer = NULL; + tbm_surface_h tbm_buffer = NULL; + Eina_List *l; + E_Output_Display_Mode display_mode; + int width, height; - /* check if output free to commit */ - if (eina_list_count(eom_output->pending_overlay_buff) != 0) - { - eom_output->pending_overlay_buff = eina_list_append(eom_output->pending_overlay_buff, outbuff); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON); - if (eom_trace_debug) - EOINF("add to pending list tdm_output:%p tdm_layer:%p tbm_surface_h:%p", eom_output->eout, - eom_output->output, eom_output->overlay_layer, outbuff->tbm_surface); + ec = ev->ec; + EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(ec)), ECORE_CALLBACK_PASS_ON); - return EINA_TRUE; - } - else + eom_client = _e_eom_client_get_current_by_ec(ec); + if (eom_client == NULL) { - layer = eom_output->overlay_layer; + eom_client = _e_eom_client_get_current_by_ec_parrent(ec); + if (eom_client == NULL) + return ECORE_CALLBACK_PASS_ON; } - if (eom_trace_debug) - { - EOINF("========================> CM START tbm_buff:%p", eom_output->eout, tbm_srfc); - EOINF("do commit tdm_output:%p tdm_layer:%p tbm_surface_h:%p", eom_output->eout, - eom_output->output, layer, outbuff->tbm_surface); - } - err = tdm_layer_set_buffer(layer, outbuff->tbm_surface); - EINA_SAFETY_ON_FALSE_GOTO(err == TDM_ERROR_NONE, error); + EINA_SAFETY_ON_NULL_RETURN_VAL(ec->pixmap, ECORE_CALLBACK_PASS_ON); - err = tdm_layer_commit(layer, _e_eom_cb_layer_commit, outbuff); - EINA_SAFETY_ON_FALSE_GOTO(err == TDM_ERROR_NONE, error2); + wl_buffer = e_pixmap_resource_get(ec->pixmap); + EINA_SAFETY_ON_NULL_RETURN_VAL(wl_buffer, ECORE_CALLBACK_PASS_ON); + EINA_SAFETY_ON_NULL_RETURN_VAL(wl_buffer->resource, ECORE_CALLBACK_PASS_ON); - eom_output->wait_overlay_buff = outbuff; + /* TODO: support different SHMEM buffers etc. */ + tbm_buffer = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, wl_buffer->resource); + EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_buffer, ECORE_CALLBACK_PASS_ON); - return EINA_TRUE; + width = tbm_surface_get_width(tbm_buffer); + height = tbm_surface_get_height(tbm_buffer); -error2: - tdm_layer_unset_buffer(layer); + if ((width <= 1) || (height <= 1)) return ECORE_CALLBACK_PASS_ON; -error: - if (outbuff) - _e_eom_output_buff_delete(outbuff); + eom_output = _e_eom_output_get_by_id(eom_client->output_id); + EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, ECORE_CALLBACK_PASS_ON); if (eom_trace_debug) - EOINF("========================> CM ENDERR tbm_buff:%p", eom_output->eout, tbm_srfc); - - return EINA_FALSE; -} + EOINF("===============> EXT START", eom_output->output); -static unsigned int -_e_eom_aligned_width_get(E_EomOutputPtr eom_output, tbm_surface_info_s *surf_info) -{ - unsigned int aligned_width = 0; - - switch (surf_info->format) + /* TODO: It works but maybe there is better solution exists ? + * Also I do not know how it affects on performance */ + if (ec->map_timer) { - case TBM_FORMAT_YUV420: - case TBM_FORMAT_YVU420: - case TBM_FORMAT_YUV422: - case TBM_FORMAT_YVU422: - case TBM_FORMAT_NV12: - case TBM_FORMAT_NV21: - aligned_width = surf_info->planes[0].stride; - break; - case TBM_FORMAT_YUYV: - case TBM_FORMAT_UYVY: - aligned_width = surf_info->planes[0].stride >> 1; - break; - case TBM_FORMAT_ARGB8888: - case TBM_FORMAT_XRGB8888: - aligned_width = surf_info->planes[0].stride >> 2; - break; - default: - EOERR("not supported format: %x", eom_output->eout, surf_info->format); + if (eom_trace_debug) + EOINF("delete map_timer", eom_output->output); + E_FREE_FUNC(ec->map_timer, ecore_timer_del); } - return aligned_width; -} - -static Eina_Bool -_e_eom_pp_info_set(E_EomOutputPtr eom_output, tbm_surface_h src, tbm_surface_h dst) -{ - tdm_error err = TDM_ERROR_NONE; - tdm_info_pp pp_info; - int x = 0, y = 0, w = 0, h = 0; - int width = 0, height = 0; - tbm_surface_info_s src_info; - tbm_surface_info_s dst_info; - unsigned int src_aligned_w; - unsigned int dst_aligned_w; - - memset(&pp_info, 0, sizeof(tdm_info_pp)); - - tbm_surface_get_info(src, &src_info); - tbm_surface_get_info(dst, &dst_info); - src_aligned_w = _e_eom_aligned_width_get(eom_output, &src_info); - dst_aligned_w = _e_eom_aligned_width_get(eom_output, &dst_info); - - width = src_aligned_w; - height = src_info.height; - - _e_eom_util_calculate_fullsize(width, height, eom_output->width, eom_output->height, - &x, &y, &w, &h); - if (eom_trace_debug) - { - EOINF("PP prentation: src:%dx%d, dst:%dx%d", eom_output->eout, src_info.width, src_info.height, dst_info.width, dst_info.height); - EOINF("PP prentation calculation: x:%d, y:%d, w:%d, h:%d", eom_output->eout, x, y, w, h); - } - - pp_info.src_config.size.h = src_aligned_w; - pp_info.src_config.size.v = src_info.height; - pp_info.src_config.pos.x = 0; - pp_info.src_config.pos.y = 0; - pp_info.src_config.pos.w = src_info.width; - pp_info.src_config.pos.h = src_info.height; - pp_info.src_config.format = src_info.format; - - pp_info.dst_config.size.h = dst_aligned_w; - pp_info.dst_config.size.v = dst_info.height; - pp_info.dst_config.pos.x = x; - pp_info.dst_config.pos.y = y; - pp_info.dst_config.pos.w = w; - pp_info.dst_config.pos.h = h; - pp_info.dst_config.format = dst_info.format; - - pp_info.transform = TDM_TRANSFORM_NORMAL; - - pp_info.sync = 0; - pp_info.flags = 0; - - if (memcmp(&eom_output->pp_overlay->pp_info, &pp_info, sizeof(tdm_info_layer))) - { - err = tdm_pp_set_info(eom_output->pp_overlay->pp, &pp_info); - EINA_SAFETY_ON_FALSE_RETURN_VAL(err == TDM_ERROR_NONE, EINA_FALSE); - memcpy(&eom_output->pp_overlay->pp_info, &pp_info, sizeof(tdm_info_layer)); - } - - return EINA_TRUE; -} - -static void -_e_eom_layer_overlay_set(E_EomOutputPtr eom_output, tbm_surface_h tsurface) -{ - tdm_info_layer layer_info, old_info; - tdm_error err = TDM_ERROR_NONE; - tbm_surface_info_s dst_info; - unsigned int width; - - CLEAR(old_info); - err = tdm_layer_get_info(eom_output->overlay_layer, &old_info); - EINA_SAFETY_ON_FALSE_RETURN(err == TDM_ERROR_NONE); - - tbm_surface_get_info(tsurface, &dst_info); - width = _e_eom_aligned_width_get(eom_output, &dst_info); - - memset(&layer_info, 0x0, sizeof(tdm_info_layer)); - layer_info.src_config.size.h = width; - layer_info.src_config.size.v = dst_info.height; - layer_info.src_config.pos.x = 0; - layer_info.src_config.pos.y = 0; - layer_info.src_config.pos.w = dst_info.width; - layer_info.src_config.pos.h = dst_info.height; - layer_info.src_config.format = dst_info.format; - layer_info.dst_pos.x = 0; - layer_info.dst_pos.y = 0; - layer_info.dst_pos.w = eom_output->width; - layer_info.dst_pos.h = eom_output->height; - layer_info.transform = TDM_TRANSFORM_NORMAL; - - if (memcmp(&old_info, &layer_info, sizeof(tdm_info_layer))) - { - err = tdm_layer_set_info(eom_output->overlay_layer, &layer_info); - EINA_SAFETY_ON_FALSE_RETURN(err == TDM_ERROR_NONE); - } -} - -static void -_e_eom_cb_pp_presentation(E_EomOutputPtr eom_output, E_EomPpDataPtr ppdata, E_EomOutputPpPtr eom_pp) -{ - E_EomBufferPtr eom_buff; - tbm_surface_h tsurface; - - eom_buff = ppdata->eom_buffer; - tsurface = ppdata->tsurface; - - E_FREE(ppdata); - - if (!eom_output) - { - tbm_surface_queue_release(eom_pp->queue, tsurface); - return; - } - - if (!e_output_connected(g_eom->output_primary)) - { - tbm_surface_queue_release(eom_pp->queue, tsurface); - return; - } + EOINF("buffer_changed callback ec:%p", eom_output->output, ec); - if (eom_output->state == MIRROR) + /* set the ec to the output for presentation. */ + if (!e_output_presentation_update(eom_output->output, eom_client->ec)) { - tbm_surface_queue_release(eom_pp->queue, tsurface); - return; + EOERR("e_output_presentation_update fails.", eom_output->output); + return ECORE_CALLBACK_PASS_ON; } -#ifdef EOM_DUMP_PRESENTATION_BUFFERS - char file[256]; - static int i; - snprintf(file, sizeof file, "%s_%d", "eom_external", i++); - tbm_surface_internal_dump_buffer(tsurface, file, i++, 0); -#endif - - _e_eom_layer_overlay_set(eom_output, tsurface); - - if (!_e_eom_output_show(eom_output, tsurface, _e_eom_tbm_buffer_release_pp_overlay, eom_buff)) + EINA_LIST_FOREACH(g_eom->clients, l, eom_client_itr) { - EOERR("pp show fail", eom_output->eout); - tbm_surface_queue_release(eom_output->pp_overlay->queue, tsurface); + if (eom_client_itr->output_id == eom_output->id) + { + display_mode = e_output_display_mode_get(eom_output->output); + wl_eom_send_output_mode(eom_client->resource, eom_output->id, _e_eom_output_mode_get(display_mode)); + } } if (eom_trace_debug) - EOINF("==============================< presentation PP", eom_output->eout); -} - -static E_EomPpDataPtr -_e_eom_pp_data_get(E_EomOutputPtr eom_output, tbm_surface_h tsurface) -{ - Eina_List *l; - E_EomPpDataPtr ppdata = NULL; - - EINA_LIST_FOREACH(eom_output->pp_overlay_data, l, ppdata) - { - if (!ppdata) continue; - - if (ppdata->tsurface == tsurface) - return ppdata; - } + EOINF("===============< EXT START", eom_output->output); - return NULL; + return ECORE_CALLBACK_PASS_ON; } static void -_e_eom_cb_pp_presentation_overlay(tdm_pp *pp, tbm_surface_h tsurface_src, tbm_surface_h tsurface_dst, void *user_data) +_e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute) { + E_EomClientPtr eom_client = NULL; E_EomOutputPtr eom_output = NULL; - E_EomPpDataPtr ppdata = NULL; - - EINA_SAFETY_ON_NULL_RETURN(user_data); - eom_output = (E_EomOutputPtr)user_data; + E_Output *primary_output = NULL; - ppdata = _e_eom_pp_data_get(eom_output, tsurface_src); - EINA_SAFETY_ON_NULL_RETURN(ppdata); - - eom_output->pp_overlay_data = eina_list_remove(eom_output->pp_overlay_data, ppdata); - - tbm_surface_internal_unref(tsurface_src); - tbm_surface_internal_unref(tsurface_dst); + eom_client = _e_eom_client_get_by_resource(resource); + EINA_SAFETY_ON_NULL_RETURN(eom_client); - eom_output->pp_overlay_converting = EINA_FALSE; + eom_output = _e_eom_output_get_by_id(output_id); + EINA_SAFETY_ON_NULL_GOTO(eom_output, no_eom_output); - if (eom_output->pp_overlay_deinit) - { - eom_output->pp_overlay_deinit = EINA_FALSE; - _e_eom_pp_deinit(eom_output); - } + EOINF("Set attribute:%d, client:%p", eom_output->output, attribute, eom_client); - if (eom_trace_debug) - EOINF("==============================> presentation PP END overlay tbm_buff:%p ppdata:%p", eom_output->eout, tsurface_dst, ppdata); + /* Bind the client with a concrete output */ + eom_client->output_id = output_id; - if (eom_output->pp_overlay == NULL) + /* Set the attribute to the eom_client */ + if (eom_output->eom_client) { - E_FREE(ppdata); - return; - } - - ppdata->tsurface = tsurface_dst; - - _e_eom_cb_pp_presentation(eom_output, ppdata, eom_output->pp_overlay); -} - -static void -_e_eom_presentation_pp_run(E_EomOutputPtr eom_output, tbm_surface_h src_surface, E_EomBufferPtr eom_buff) -{ - tdm_error tdm_err = TDM_ERROR_NONE; - tbm_surface_h dst_surface = NULL; - Eina_Bool ret = EINA_FALSE; - E_EomOutputPpPtr eom_pp = NULL; - E_EomPpDataPtr ppdata = NULL; - - if (!e_output_connected(g_eom->output_primary)) - return; + // if eom_ouitput->eom_client == eom_client + if (eom_output->eom_client == eom_client) + { + /* Current client can set any flag it wants */ + _e_eom_output_attribute_force_set(eom_output, attribute); + + if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE) + wl_eom_send_output_attribute(eom_client->resource, eom_output->id, + _e_eom_output_attribute_get(eom_output), + EOM_OUTPUT_ATTRIBUTE_STATE_LOST, + EOM_ERROR_NONE); + } + else + { + /* A client is trying to set new attribute */ + if (!_e_eom_output_attribute_set(eom_output, attribute)) + { + EOINF("client failed to set attribute", eom_output->output); + wl_eom_send_output_attribute(eom_client->resource, eom_output->id, + _e_eom_output_attribute_get(eom_output), + EOM_OUTPUT_ATTRIBUTE_STATE_LOST, + EOM_ERROR_INVALID_PARAMETER); + return; + } - eom_pp = eom_output->pp_overlay; + EOINF("Send changes to previous current client", eom_output->output); + /* eom_output->eom_client is lost the attribute */ + wl_eom_send_output_attribute(eom_output->eom_client->resource, eom_output->id, + _e_eom_output_attribute_get(eom_output), + EOM_OUTPUT_ATTRIBUTE_STATE_LOST, + EOM_ERROR_NONE); - if (!eom_pp || !eom_pp->pp || !eom_pp->queue) - { - EOERR("no pp data", eom_output->eout); - _e_eom_buffer_destroy(eom_output, eom_buff); - return; + eom_output->eom_client->current = EINA_FALSE; + eom_output->eom_client = NULL; + } } - - ppdata = E_NEW(E_EomPpData, 1); - if (!ppdata) + else { - EOERR("make pp data fail", eom_output->eout); - _e_eom_buffer_destroy(eom_output, eom_buff); - return; + /* Current client can set any flag it wants */ + _e_eom_output_attribute_force_set(eom_output, attribute); } - ppdata->eom_output = eom_output; - ppdata->eom_buffer = eom_buff; - ppdata->tsurface = src_surface; - if (!tbm_surface_queue_can_dequeue(eom_pp->queue, 0)) + /* set the output display_mode */ + if (_e_eom_output_attribute_get(eom_output) == EOM_OUTPUT_ATTRIBUTE_NONE) { - if (eom_trace_debug) - EOINF("all pp buffers are busy, wait release queue(%p)", eom_output->eout, eom_pp->queue); + if (e_output_presentation_ec_get(eom_output->output) == eom_client->ec) + e_output_presentation_unset(eom_output->output); - eom_output->pending_pp_overlay = eina_list_append(eom_output->pending_pp_overlay, ppdata); + primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen); + if (!e_output_mirror_set(eom_output->output, primary_output)) + { + EOERR("e_output_mirror_set fails", eom_output->output); + goto no_eom_output; + } + /* broadcast the status */ + _e_eom_output_status_broadcast(eom_output, NULL, EOM_OUTPUT_ATTRIBUTE_STATE_NONE); return; } - - tdm_err = tbm_surface_queue_dequeue(eom_pp->queue, &dst_surface); - EINA_SAFETY_ON_FALSE_GOTO(tdm_err == TDM_ERROR_NONE, error); - - if (eom_trace_debug) - EOINF("============================> presentation PP START tbm_buff:%p ppdata:%p", eom_output->eout, dst_surface, ppdata); - - ret = _e_eom_pp_info_set(eom_output, src_surface, dst_surface); - EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, error); - - eom_output->pp_overlay_data = eina_list_append(eom_output->pp_overlay_data, ppdata); - - tdm_err = tdm_pp_set_done_handler(eom_pp->pp, _e_eom_cb_pp_presentation_overlay, eom_output); - EINA_SAFETY_ON_FALSE_GOTO(tdm_err == TDM_ERROR_NONE, error); - - tbm_surface_internal_ref(src_surface); - tbm_surface_internal_ref(dst_surface); - - tdm_err = tdm_pp_attach(eom_pp->pp, src_surface, dst_surface); - EINA_SAFETY_ON_FALSE_GOTO(tdm_err == TDM_ERROR_NONE, attach_fail); - - eom_output->pp_overlay_converting = EINA_TRUE; - - tdm_err = tdm_pp_commit(eom_pp->pp); - EINA_SAFETY_ON_FALSE_GOTO(tdm_err == TDM_ERROR_NONE, commit_fail); - - if (eom_trace_debug) + else { - EOINF("do presentation pp commit tdm_output:%p tbm_surface_h(src:%p dst:%p)", eom_output->eout, - eom_output->output, src_surface, dst_surface); - EOERR("============================< presentation PP done tbm_buff:%p", eom_output->eout, dst_surface); - } - - return; - -commit_fail: - eom_output->pp_overlay_converting = EINA_FALSE; - -attach_fail: - tbm_surface_internal_unref(dst_surface); - tbm_surface_internal_unref(src_surface); + /* Set the client as current client of the eom_output */ + eom_client->current = EINA_TRUE; + eom_output->eom_client = eom_client; -error: - EOERR("failed run pp tdm error: %d", eom_output->eout, tdm_err); - - eom_output->pp_overlay_data = eina_list_remove(eom_output->pp_overlay_data, ppdata); + if (e_output_presentation_wait_set(eom_output->output, eom_client->ec)) + { + EOERR("e_output_presentation_wait_set fails\n", NULL); + return; + } - if (dst_surface) - { - if (eom_trace_debug) - EOINF("============================> presentation PP ENDERR tbm_buff:%p", eom_output->eout, dst_surface); - tbm_surface_queue_release(eom_pp->queue, dst_surface); + /* Send changes to the caller-client */ + wl_eom_send_output_attribute(eom_client->resource, eom_output->id, + _e_eom_output_attribute_get(eom_output), + EOM_OUTPUT_ATTRIBUTE_STATE_NONE, + EOM_ERROR_NONE); } - _e_eom_buffer_destroy(eom_output, eom_buff); - - E_FREE(ppdata); -} + return; -static E_EomClientPtr -_e_eom_client_get_current_by_id(int id) -{ - Eina_List *l; - E_EomClientPtr client; +no_eom_output: + /* Get here if EOM does not have output referred by output_id */ + wl_eom_send_output_attribute(eom_client->resource, output_id, + EOM_OUTPUT_ATTRIBUTE_NONE, + EOM_OUTPUT_ATTRIBUTE_STATE_NONE, + EOM_ERROR_NO_SUCH_DEVICE); - EINA_LIST_FOREACH(g_eom->clients, l, client) - { - if (client && - client->current == EINA_TRUE && - client->output_id == id) - return client; - } + wl_eom_send_output_mode(eom_client->resource, output_id, EOM_OUTPUT_MODE_NONE); - return NULL; + wl_eom_send_output_type(eom_client->resource, output_id, + EOM_OUTPUT_ATTRIBUTE_STATE_NONE, + TDM_OUTPUT_CONN_STATUS_DISCONNECTED); } static void -_e_eom_output_overlay_buff_release(E_EomOutputPtr eom_output) +_e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface) { - Eina_List *l, *ll; - E_EomOutputBufferPtr buff = NULL; - E_EomPpDataPtr ppdata = NULL; + E_EomOutputPtr eom_output = NULL; + E_EomClientPtr eom_client = NULL; + E_Client *ec = NULL; - EINA_LIST_FOREACH_SAFE(eom_output->pending_overlay_buff, l, ll, buff) + if (!(ec = wl_resource_get_user_data(surface))) { - if (eom_trace_debug) - EOINF("delete pending overlay tbm_buff:%p", eom_output->eout, buff->tbm_surface); - eom_output->pending_overlay_buff = eina_list_remove_list(eom_output->pending_overlay_buff, l); - _e_eom_output_buff_delete(buff); + wl_resource_post_error(surface, WL_DISPLAY_ERROR_INVALID_OBJECT, "No Client For Shell Surface"); + return; } - eina_list_free(eom_output->pending_overlay_buff); - eom_output->wait_overlay_buff = NULL; - if (eom_trace_debug) - EOINF("delete show overlay tbm_buff:%p", eom_output->eout, eom_output->show_overlay_buff ? eom_output->show_overlay_buff->tbm_surface : NULL); - _e_eom_output_buff_delete(eom_output->show_overlay_buff); - eom_output->show_overlay_buff = NULL; + EOINF("set shell output id:%d resource:%p surface:%p", NULL, output_id, resource, surface); - EINA_LIST_FOREACH_SAFE(eom_output->pending_pp_overlay, l, ll, ppdata) - { - if (eom_trace_debug) - EOINF("delete pending overlay pp data:%p", eom_output->eout, ppdata); - eom_output->pending_pp_overlay = eina_list_remove_list(eom_output->pending_pp_overlay, l); - _e_eom_buffer_destroy(eom_output, ppdata->eom_buffer); - E_FREE(ppdata); - } - eina_list_free(eom_output->pending_pp_overlay); - eom_output->pending_pp_overlay = NULL; -} + eom_client = _e_eom_client_get_by_resource(resource); + EINA_SAFETY_ON_NULL_RETURN(eom_client); -static E_EomOutputPtr -_e_eom_output_find(E_Output *output) -{ - E_EomOutputPtr eom_output = NULL, eom_output_tmp = NULL; - Eina_List *l; + /* ec is used in buffer_change callback for distinguishing external ec and its buffers */ + eom_client->ec = ec; - EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output_tmp) + eom_output = _e_eom_output_get_by_id(output_id); + if (eom_output == NULL) { - if (eom_output_tmp->output == output->toutput) - eom_output = eom_output_tmp; + wl_eom_send_output_set_window(resource, output_id, WL_EOM_ERROR_NO_OUTPUT); + EOERR("no eom_output error\n", NULL); + return; } - return eom_output; -} - -static E_EomOutputPtr -_e_eom_output_find_added_output(E_Output *output) -{ - E_EomOutputPtr eom_output = NULL, eom_output_tmp = NULL; - Eina_List *l; - - EINA_LIST_FOREACH(g_eom->added_outputs, l, eom_output_tmp) + if (ec == e_output_presentation_ec_get(eom_output->output)) { - if (eom_output_tmp->output == output->toutput) - eom_output = eom_output_tmp; + wl_eom_send_output_set_window(resource, output_id, WL_EOM_ERROR_OUTPUT_OCCUPIED); + return; } - return eom_output; + _e_eom_output_send_configure_event(eom_output, ec); + + wl_eom_send_output_set_window(resource, output_id, WL_EOM_ERROR_NONE); } -static Eina_Bool -_e_eom_create(E_Output *output, Eina_Bool added) +static void +_e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id) { E_EomOutputPtr eom_output = NULL; + int w, h, pw, ph; - if (!g_eom) return EINA_TRUE; - - eom_output = E_NEW(E_EomOutput, 1); - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, EINA_FALSE); - - eom_output->id = output->index; - eom_output->mode = EOM_OUTPUT_MODE_NONE; - eom_output->connection = WL_EOM_STATUS_NONE; - eom_output->eout = output; - EINA_SAFETY_ON_NULL_GOTO(eom_output->eout, err); + EOINF("get output info:%d", NULL, output_id); - eom_output->output = output->toutput; - eom_output->type = (eom_output_type_e)output->toutput_type; + eom_output = _e_eom_output_get_by_id(output_id); + EINA_SAFETY_ON_FALSE_RETURN(eom_output); - eom_output->connection_status = EINA_FALSE; - eom_output->width = 0; - eom_output->height = 0; - eom_output->phys_width = 0; - eom_output->phys_height = 0; - eom_output->added = added; - - if (eom_output->added) - g_eom->added_outputs = eina_list_append(g_eom->added_outputs, eom_output); - else - g_eom->eom_outputs = eina_list_append(g_eom->eom_outputs, eom_output); - - EOINF("create (%d)output, type:%d, name:%s added:%d", eom_output->eout, - eom_output->id, eom_output->type, eom_output->name, eom_output->added); - - return EINA_TRUE; - -err: - E_FREE(eom_output); - - return EINA_FALSE; -} - -static Eina_Bool -_e_eom_destroy(E_Output *output) -{ - E_EomOutputPtr eom_output = NULL; - - if (!g_eom) return EINA_TRUE; - - eom_output = _e_eom_output_find_added_output(output); - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, EINA_FALSE); - - EOINF("destroy (%d)output, type:%d, name:%s added:%d", eom_output->eout, - eom_output->id, eom_output->type, eom_output->name, eom_output->added); - - if (eom_output->added) - g_eom->added_outputs = eina_list_remove(g_eom->added_outputs, eom_output); - else - g_eom->eom_outputs = eina_list_remove(g_eom->eom_outputs, eom_output); - - E_FREE(eom_output); - - return EINA_TRUE; -} - -static void -_e_eom_output_deinit(void) -{ - E_EomOutputPtr eom_output; - Eina_List *l; - - if (!g_eom) return; - if (!g_eom->eom_outputs) return; - - EINA_LIST_FOREACH(g_eom->added_outputs, l, eom_output) - _e_eom_destroy(eom_output->eout); - - eina_list_free(g_eom->eom_outputs); - g_eom->added_outputs = NULL; - - EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) - _e_eom_destroy(eom_output->eout); - - eina_list_free(g_eom->eom_outputs); - g_eom->eom_outputs = NULL; -} - -static Eina_Bool -_e_eom_output_init(void) -{ - E_Comp_Screen *e_comp_screen = NULL; - E_Output *output = NULL; - Eina_List *l; - - EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE); - - e_comp_screen = e_comp->e_comp_screen; - EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE); - - g_eom->eom_output_count = e_comp_screen->num_outputs - 1; - EOINF("external output count : %d", NULL, g_eom->eom_output_count); - - /* create the eom_output except for the primary output */ - EINA_LIST_FOREACH(e_comp_screen->outputs, l, output) - { - if (!output) continue; - if (output == g_eom->output_primary) continue; - - if (!_e_eom_create(output, EINA_FALSE)) - { - EOERR("_e_eom_create fails.", output); - goto err; - } - } - - return EINA_TRUE; - -err: - _e_eom_output_deinit(); - - return EINA_FALSE; -} - -static Eina_Bool -_e_eom_boot_connection_check(void *data) -{ - E_EomOutputPtr eom_output; - E_Output *eout = NULL; - Eina_List *l; - - if (g_eom->check_first_boot != 0) - { - g_eom->timer = NULL; - return ECORE_CALLBACK_CANCEL; - } - - g_eom->check_first_boot = 1; - - EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) - { - if (eom_output->id == 0) - continue; - - eout = eom_output->eout; - - if (!e_output_connected(eout)) continue; - - e_output_external_update(eout); - } - - g_eom->timer = NULL; - - return ECORE_CALLBACK_CANCEL; -} - -static Eina_Bool -_e_eom_presentation_check(void *data) -{ - E_EomOutputPtr eom_output = NULL; - - if (!data) return ECORE_CALLBACK_CANCEL; - - eom_output = (E_EomOutputPtr)data; - - eom_output->delay_timer = NULL; - - if (eom_output->state == WAIT_PRESENTATION) - e_output_external_set(eom_output->eout, E_OUTPUT_DISPLAY_MODE_MIRROR); - - return ECORE_CALLBACK_CANCEL; -} - -static E_EomClientPtr -_e_eom_client_get_by_resource(struct wl_resource *resource) -{ - Eina_List *l; - E_EomClientPtr client; - - EINA_LIST_FOREACH(g_eom->clients, l, client) - { - if (client && client->resource == resource) - return client; - } - - return NULL; -} - -static E_EomOutputPtr -_e_eom_output_get_by_id(int id) -{ - E_EomOutputPtr eom_output; - Eina_List *l; - - EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) - { - if (eom_output && eom_output->id == id) - return eom_output; - } - - return NULL; -} - -static E_EomOutputPtr -_e_eom_output_by_ec_child_get(E_Client *ec) -{ - E_EomOutputPtr eom_output = NULL; - E_EomClientPtr eom_client = NULL; - E_Client *parent = NULL; - Eina_List *l; - - EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) - { - eom_client = _e_eom_client_get_current_by_id(eom_output->id); - if (!eom_client) - continue; - - if (eom_client->ec == ec) - return eom_output; - - if (!ec->comp_data || !ec->comp_data->sub.data) - continue; - - parent = ec->comp_data->sub.data->parent; - while (parent) - { - if (parent == eom_client->ec) - return eom_output; - - if (!parent->comp_data || !parent->comp_data->sub.data) - break; - - parent = parent->comp_data->sub.data->parent; - } - } - - return NULL; -} - -static void -_e_eom_cb_wl_eom_client_destroy(struct wl_resource *resource) -{ - E_EomClientPtr client = NULL; - E_EomOutputPtr eom_output = NULL; - E_Output *output = NULL; - E_Plane *ep = NULL; - - EOINF("=======================> CLIENT DESTROY", NULL); - - EINA_SAFETY_ON_NULL_RETURN(resource); - - client = _e_eom_client_get_by_resource(resource); - EINA_SAFETY_ON_NULL_RETURN(client); - - g_eom->clients = eina_list_remove(g_eom->clients, client); - - if (client->current == EINA_FALSE) - goto end2; - - eom_output = _e_eom_output_get_by_id(client->output_id); - EINA_SAFETY_ON_NULL_GOTO(eom_output, end2); - - _e_eom_output_state_set_attribute(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE); - - if (eom_output->state == NONE) - goto end; - - if (eom_output->state == WAIT_PRESENTATION) - { - eom_output->state = NONE; - goto end; - } - - if (eom_output->overlay_layer) - { - tdm_error err = TDM_ERROR_NONE; - - err = tdm_layer_unset_buffer(eom_output->overlay_layer); - if (err != TDM_ERROR_NONE) - EOERR("fail unset buffer:%d", eom_output->eout, err); - - err = tdm_layer_commit(eom_output->overlay_layer, NULL, eom_output); - if (err != TDM_ERROR_NONE) - EOERR("fail commit on deleting output err:%d", eom_output->eout, err); - } - _e_eom_output_overlay_buff_release(eom_output); - - if (!eom_output->pp_overlay_converting) - _e_eom_pp_deinit(eom_output); - else - eom_output->pp_overlay_deinit = EINA_TRUE; - - if (e_output_connected(eom_output->eout)) - { - EOINF("Start Mirroring", eom_output->eout); - e_output_external_set(output, E_OUTPUT_DISPLAY_MODE_MIRROR); - eom_output->state = MIRROR; - - ep = e_output_default_fb_target_get(eom_output->eout); - if (ep->prepare_ec) - { - e_plane_ec_prepare_set(ep, NULL); - e_plane_ec_set(ep, NULL); - } - } -end: - /* Notify eom clients which are binded to a concrete output that the - * state and mode of the output has been changed */ - _e_eom_output_status_broadcast(eom_output, client, EOM_OUTPUT_ATTRIBUTE_STATE_NONE); - -end2: - free(client); -} - -static Eina_Bool -_e_eom_mirror_start(E_EomOutput *eom_output, E_EomClient *eom_client) -{ - E_Output *output = NULL; - E_Plane *ep = NULL; - - eom_client->current = EINA_FALSE; - output = eom_output->eout; - - _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE); - - if (e_output_connected(output)) - { - EOINF("Start Mirroring", eom_output->eout); - e_output_external_set(output, E_OUTPUT_DISPLAY_MODE_MIRROR); - eom_output->state = MIRROR; - - ep = e_output_default_fb_target_get(output); - - if (ep->prepare_ec) - { - e_plane_ec_prepare_set(ep, NULL); - e_plane_ec_set(ep, NULL); - } - - if (eom_output->overlay_layer) - { - tdm_error err = TDM_ERROR_NONE; - - err = tdm_layer_unset_buffer(eom_output->overlay_layer); - if (err != TDM_ERROR_NONE) - EOERR("fail unset buffer:%d", eom_output->eout, err); - - err = tdm_layer_commit(eom_output->overlay_layer, NULL, eom_output); - if (err != TDM_ERROR_NONE) - EOERR("fail commit on deleting output err:%d", eom_output->eout, err); - } - _e_eom_output_overlay_buff_release(eom_output); - - if (!eom_output->pp_overlay_converting) - _e_eom_pp_deinit(eom_output); - else - eom_output->pp_overlay_deinit = EINA_TRUE; - } - /* If mirror mode has been run notify all clients about that */ - if (eom_trace_debug) - EOINF("client set NONE attribute, send new info to previous current client", eom_output->eout); - - /* broadcast the status */ - _e_eom_output_status_broadcast(eom_output, NULL, EOM_OUTPUT_ATTRIBUTE_STATE_NONE); - - return EINA_TRUE; -} - -static void -_e_eom_cb_wl_request_set_attribute_result_send(E_EomOutput *eom_output, E_EomClient *eom_client) -{ - E_EomClientPtr current_eom_client = NULL; - E_Output *output = NULL; - E_Plane *ep = NULL; - - /* Send changes to the caller-client */ - wl_eom_send_output_attribute(eom_client->resource, eom_output->id, - _e_eom_output_state_get_attribute(eom_output), - EOM_OUTPUT_ATTRIBUTE_STATE_NONE, - EOM_ERROR_NONE); - - current_eom_client = _e_eom_client_get_current_by_id(eom_output->id); - EOINF("Substitute current client: new:%p, old:%p", NULL, eom_client, current_eom_client); - - /* Send changes to previous current client */ - if (eom_client->current == EINA_FALSE && current_eom_client) - { - EOINF("Send changes to previous current client", eom_output->eout); - - wl_eom_send_output_attribute(current_eom_client->resource, eom_output->id, - _e_eom_output_state_get_attribute(eom_output), - EOM_OUTPUT_ATTRIBUTE_STATE_LOST, - EOM_ERROR_NONE); - - current_eom_client->current = EINA_FALSE; - - output = eom_output->eout; - - if (e_output_connected(output)) - { - EOINF("Start Mirroring", eom_output->eout); - e_output_external_set(output, E_OUTPUT_DISPLAY_MODE_MIRROR); - eom_output->state = MIRROR; - - ep = e_output_default_fb_target_get(eom_output->eout); - - if (ep->prepare_ec) - { - e_plane_ec_prepare_set(ep, NULL); - e_plane_ec_set(ep, NULL); - } - - if (eom_output->overlay_layer) - { - tdm_error err = TDM_ERROR_NONE; - - err = tdm_layer_unset_buffer(eom_output->overlay_layer); - if (err != TDM_ERROR_NONE) - EOERR("fail unset buffer:%d", eom_output->eout, err); - - err = tdm_layer_commit(eom_output->overlay_layer, NULL, eom_output); - if (err != TDM_ERROR_NONE) - EOERR("fail commit on deleting output err:%d", eom_output->eout, err); - } - _e_eom_output_overlay_buff_release(eom_output); - - if (!eom_output->pp_overlay_converting) - _e_eom_pp_deinit(eom_output); - else - eom_output->pp_overlay_deinit = EINA_TRUE; - } - } - - /* Set the client as current client of the eom_output */ - eom_client->current = EINA_TRUE; - - if (eom_output->connection_status == EINA_FALSE) - eom_output->state = WAIT_PRESENTATION; - else - { - if (eom_output->delay_timer) - { - ecore_timer_del(eom_output->delay_timer); - eom_output->delay_timer = ecore_timer_add(EOM_DELAY_CHECK_TIMEOUT, _e_eom_presentation_check, eom_output); - } - } -} - -static void -_e_eom_cb_wl_request_set_attribute(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, uint32_t attribute) -{ - eom_error_e eom_error = EOM_ERROR_NONE; - E_EomClientPtr eom_client = NULL;//, current_eom_client = NULL, iterator = NULL; - E_EomOutputPtr eom_output = NULL; - Eina_Bool ret = EINA_FALSE; - - eom_client = _e_eom_client_get_by_resource(resource); - EINA_SAFETY_ON_NULL_RETURN(eom_client); - - /* Bind the client with a concrete output */ - eom_client->output_id = output_id; - - eom_output = _e_eom_output_get_by_id(output_id); - EINA_SAFETY_ON_NULL_GOTO(eom_output, no_eom_output); - - EOINF("Set attribute:%d, client:%p", eom_output->eout, attribute, eom_client); - - if (eom_client->current == EINA_TRUE && eom_output->id == eom_client->output_id) - { - /* Current client can set any flag it wants */ - _e_eom_output_state_set_force_attribute(eom_output, attribute); - } - else if (eom_output->id == eom_client->output_id) - { - /* A client is trying to set new attribute */ - ret = _e_eom_output_state_set_attribute(eom_output, attribute); - if (ret == EINA_FALSE) - { - EOINF("client failed to set attribute", eom_output->eout); - eom_error = EOM_ERROR_INVALID_PARAMETER; - wl_eom_send_output_attribute(eom_client->resource, eom_output->id, - _e_eom_output_state_get_attribute(eom_output), - EOM_OUTPUT_ATTRIBUTE_STATE_LOST, - eom_error); - return; - } - } - else - return; - - if (attribute == EOM_OUTPUT_ATTRIBUTE_NONE && eom_output->state != MIRROR) - { - if (!_e_eom_mirror_start(eom_output, eom_client)) - { - EOINF("mirror start FAILED", eom_output->eout); - return; - } - - wl_eom_send_output_attribute(eom_client->resource, eom_output->id, - _e_eom_output_state_get_attribute(eom_output), - EOM_OUTPUT_ATTRIBUTE_STATE_LOST, - eom_error); - return; - } - - _e_eom_cb_wl_request_set_attribute_result_send(eom_output, eom_client); - - return; - - /* Get here if EOM does not have output referred by output_id */ -no_eom_output: - wl_eom_send_output_attribute(eom_client->resource, output_id, - EOM_OUTPUT_ATTRIBUTE_NONE, - EOM_OUTPUT_ATTRIBUTE_STATE_NONE, - EOM_ERROR_NO_SUCH_DEVICE); - - wl_eom_send_output_mode(eom_client->resource, output_id, - EOM_OUTPUT_MODE_NONE); - - wl_eom_send_output_type(eom_client->resource, output_id, - EOM_OUTPUT_ATTRIBUTE_STATE_NONE, - TDM_OUTPUT_CONN_STATUS_DISCONNECTED); -} - -static Eina_Bool -_e_eom_cb_comp_object_redirected(void *data, E_Client *ec) -{ - E_EomCompObjectInterceptHookData *hook_data; - - EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_TRUE); - - hook_data = (E_EomCompObjectInterceptHookData* )data; - - if (!hook_data->ec || !hook_data->hook) - return EINA_TRUE; - - if (hook_data->ec != ec) - return EINA_TRUE; - - /* Hide the window from Enlightenment main screen */ - e_client_redirected_set(ec, EINA_FALSE); - - e_comp_object_intercept_hook_del(hook_data->hook); - - g_eom->comp_object_intercept_hooks = eina_list_remove(g_eom->comp_object_intercept_hooks, hook_data); - - free(hook_data); - - return EINA_TRUE; -} - -static Eina_Bool -_e_eom_util_add_comp_object_redirected_hook(E_Client *ec) -{ - E_EomCompObjectInterceptHookData *hook_data = NULL; - E_Comp_Object_Intercept_Hook *hook = NULL; - - hook_data = E_NEW(E_EomCompObjectInterceptHookData, 1); - EINA_SAFETY_ON_NULL_GOTO(hook_data, err); - - hook_data->ec = ec; - - hook = e_comp_object_intercept_hook_add(E_COMP_OBJECT_INTERCEPT_HOOK_SHOW_HELPER, - _e_eom_cb_comp_object_redirected, hook_data); - EINA_SAFETY_ON_NULL_GOTO(hook, err); - - hook_data->hook = hook; - - g_eom->comp_object_intercept_hooks = eina_list_append(g_eom->comp_object_intercept_hooks, hook_data); - - return EINA_TRUE; - -err: - if (hook_data) - free(hook_data); - - return EINA_FALSE; -} - -static void -_e_eom_send_configure_event() -{ - E_EomOutput *eom_output = NULL; - E_EomClientPtr eom_client = NULL; - E_Client *ec = NULL; - Eina_List *l; - Eina_Bool ret = EINA_FALSE; - E_Comp_Client_Data *cdata = NULL; - E_Plane *ep = NULL; - - EINA_LIST_FOREACH(g_eom->clients, l, eom_client) - { - if (eom_client->current == EINA_TRUE) - { - EINA_SAFETY_ON_NULL_RETURN(eom_client->ec); - - ec = eom_client->ec; - - cdata = ec->comp_data; - EINA_SAFETY_ON_NULL_RETURN(cdata); - EINA_SAFETY_ON_NULL_RETURN(cdata->shell.configure_send); - - eom_output = _e_eom_output_get_by_id(eom_client->output_id); - if (eom_output == NULL) - { - EOERR("no eom_output error\n", NULL); - return; - } - - EOINF("e_comp_object_redirected_set (ec:%p)(ec->frame:%p)\n", eom_output->eout, ec, ec->frame); - ret = _e_eom_util_add_comp_object_redirected_hook(eom_client->ec); - EINA_SAFETY_ON_FALSE_RETURN(ret == EINA_TRUE); - - cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height); - - ep = e_output_default_fb_target_get(eom_output->eout); - e_plane_ec_prepare_set(ep, ec); - - return; - } - } -} - -static void -_e_eom_window_set_internal(struct wl_resource *resource, int output_id, E_Client *ec) -{ - E_EomOutputPtr eom_output = NULL; - E_EomClientPtr eom_client = NULL; - E_Comp_Client_Data *cdata = NULL; - Eina_Bool ret = EINA_FALSE; - E_Plane *ep = NULL; - - if (!resource || output_id <= 0 || !ec || e_object_is_del(E_OBJECT(ec))) - return; - - eom_client = _e_eom_client_get_by_resource(resource); - EINA_SAFETY_ON_NULL_RETURN(eom_client); - - eom_output = _e_eom_output_get_by_id(output_id); - if (eom_output == NULL) - { - wl_eom_send_output_set_window(resource, output_id, WL_EOM_ERROR_NO_OUTPUT); - EOERR("no eom_output error\n", NULL); - return; - } - - if (!eom_client->current) - { - wl_eom_send_output_set_window(resource, output_id, WL_EOM_ERROR_OUTPUT_OCCUPIED); - return; - } - - ret = _e_eom_util_add_comp_object_redirected_hook(ec); - EINA_SAFETY_ON_FALSE_RETURN(ret == EINA_TRUE); - - EOINF("e_comp_object_redirected_set (ec:%p)(ec->frame:%p)\n", eom_output->eout, ec, ec->frame); - - /* ec is used in buffer_change callback for distinguishing external ec and its buffers */ - eom_client->ec = ec; - - /* Send reconfigure event to a client which will resize its window to - * external output resolution in respond */ - cdata = ec->comp_data; - EINA_SAFETY_ON_NULL_RETURN(cdata); - EINA_SAFETY_ON_NULL_RETURN(cdata->shell.configure_send); - - cdata->shell.configure_send(ec->comp_data->shell.surface, 0, eom_output->width, eom_output->height); - - ep = e_output_default_fb_target_get(eom_output->eout); - e_plane_ec_prepare_set(ep, ec); - - wl_eom_send_output_set_window(resource, output_id, WL_EOM_ERROR_NONE); -} - -static void -_e_eom_cb_wl_request_set_shell_window(struct wl_client *client, struct wl_resource *resource, uint32_t output_id, struct wl_resource *surface) -{ - E_Client *ec = NULL; - - if (resource == NULL || output_id <= 0 || surface == NULL) - return; - - EOINF("set shell output id:%d resource:%p surface:%p", NULL, output_id, resource, surface); - - if (!(ec = wl_resource_get_user_data(surface))) - { - wl_resource_post_error(surface, WL_DISPLAY_ERROR_INVALID_OBJECT, "No Client For Shell Surface"); - return; - } - - _e_eom_window_set_internal(resource, output_id, ec); -} - -static void -_e_eom_cb_wl_request_get_output_info(struct wl_client *client, struct wl_resource *resource, uint32_t output_id) -{ - E_EomOutputPtr eom_output = NULL; - - EOINF("get output info:%d", NULL, output_id); - - eom_output = _e_eom_output_get_by_id(output_id); - EINA_SAFETY_ON_FALSE_RETURN(eom_output); - - wl_eom_send_output_info(resource, eom_output->id, eom_output->type, eom_output->mode, eom_output->width, eom_output->height, - eom_output->phys_width, eom_output->phys_height, eom_output->connection, - 1, 0, 0, 0); - - EOINF("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d", NULL, - eom_output->id, eom_output->type, eom_output->mode, eom_output->width, eom_output->height, - eom_output->phys_width, eom_output->phys_height, eom_output->connection_status); -} - -static const struct wl_eom_interface _e_eom_wl_implementation = -{ - _e_eom_cb_wl_request_set_attribute, - _e_eom_cb_wl_request_set_shell_window, - _e_eom_cb_wl_request_get_output_info -}; - -static void -_e_eom_cb_wl_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) -{ - struct wl_resource *resource = NULL; - E_EomPtr eom = NULL; - E_EomClientPtr new_client = NULL; - E_EomOutputPtr eom_output = NULL; - Eina_List *l; - - EINA_SAFETY_ON_NULL_RETURN(data); - eom = data; - - resource = wl_resource_create(client, &wl_eom_interface, MIN(version, 1), id); - if (resource == NULL) - { - EOERR("resource is null. (version :%d, id:%d)", NULL, version, id); - wl_client_post_no_memory(client); - return; - } - - wl_resource_set_implementation(resource, &_e_eom_wl_implementation, eom, _e_eom_cb_wl_eom_client_destroy); - - wl_eom_send_output_count(resource, g_eom->eom_output_count); - - EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) - { - if (!eom_output) continue; - - wl_eom_send_output_info(resource, eom_output->id, eom_output->type, eom_output->mode, eom_output->width, eom_output->height, - eom_output->phys_width, eom_output->phys_height, eom_output->connection, - 1, 0, 0, 0); - - EOINF("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d", eom_output->eout, - eom_output->id, eom_output->type, eom_output->mode, eom_output->width, eom_output->height, - eom_output->phys_width, eom_output->phys_height, eom_output->connection_status); - } - - new_client = E_NEW(E_EomClient, 1); - EINA_SAFETY_ON_NULL_RETURN(new_client); - - new_client->resource = resource; - new_client->current = EINA_FALSE; - new_client->output_id = -1; - new_client->ec = NULL; - - g_eom->clients = eina_list_append(g_eom->clients, new_client); - - EOINF("=======================> BIND CLIENT", NULL); -} - -static E_EomClientPtr -_e_eom_client_get_current_by_ec(E_Client *ec) -{ - Eina_List *l; - E_EomClientPtr client; - - EINA_LIST_FOREACH(g_eom->clients, l, client) - { - if (client && client->current == EINA_TRUE && client->ec == ec) - return client; - } - - return NULL; -} - -static void -_e_eom_tbm_buffer_release_ext_mod(E_EomOutputPtr eom_output, tbm_surface_h srfc, void *eom_buff) -{ - if (eom_trace_debug) - EOINF("============> EXT END tbm_buff:%p E_EomBuffer:%p", eom_output->eout, srfc, eom_buff); - _e_eom_buffer_destroy(eom_output, eom_buff); -} - -static E_EomClientPtr -_e_eom_client_get_current_by_ec_parrent(E_Client *ec) -{ - Eina_List *l; - E_EomClientPtr client; - E_Client *parent = NULL; - - if (!ec->comp_data || !ec->comp_data->sub.data) - return NULL; - - EINA_LIST_FOREACH(g_eom->clients, l, client) - { - parent = ec->comp_data->sub.data->parent; - while (parent) - { - if (client->ec == parent) - return client; - - if (!parent->comp_data || !parent->comp_data->sub.data) - break; - - parent = parent->comp_data->sub.data->parent; - } - } - - return NULL; -} - -static Eina_Bool -_e_eom_cb_client_buffer_change(void *data, int type, void *event) -{ - E_Comp_Wl_Buffer *wl_buffer = NULL; - E_EomClientPtr eom_client = NULL, eom_client_itr = NULL; - E_EomOutputPtr eom_output = NULL; - E_Event_Client *ev = event; - E_Client *ec = NULL; - tbm_surface_h tbm_buffer = NULL; - Eina_List *l; - Eina_Bool overlay = EINA_FALSE; - int width, height; - - 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; - EINA_SAFETY_ON_TRUE_RETURN_VAL(e_object_is_del(E_OBJECT(ec)), - ECORE_CALLBACK_PASS_ON); - - eom_client = _e_eom_client_get_current_by_ec(ec); - if (eom_client == NULL) - { - eom_client = _e_eom_client_get_current_by_ec_parrent(ec); - if (eom_client == NULL) - return ECORE_CALLBACK_PASS_ON; - - overlay = EINA_TRUE; - } - - EINA_SAFETY_ON_NULL_RETURN_VAL(ec->pixmap, ECORE_CALLBACK_PASS_ON); - - wl_buffer = e_pixmap_resource_get(ec->pixmap); - EINA_SAFETY_ON_NULL_RETURN_VAL(wl_buffer, ECORE_CALLBACK_PASS_ON); - EINA_SAFETY_ON_NULL_RETURN_VAL(wl_buffer->resource, ECORE_CALLBACK_PASS_ON); - - /* TODO: support different SHMEM buffers etc. */ - tbm_buffer = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, wl_buffer->resource); - EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_buffer, ECORE_CALLBACK_PASS_ON); - - width = tbm_surface_get_width(tbm_buffer); - height = tbm_surface_get_height(tbm_buffer); - - if ((width <= 1) || (height <= 1)) - return ECORE_CALLBACK_PASS_ON; - - eom_output = _e_eom_output_get_by_id(eom_client->output_id); - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_output, ECORE_CALLBACK_PASS_ON); - - if (eom_trace_debug) - EOINF("===============> EXT START", eom_output->eout); - - if (eom_output->delay_timer) - ecore_timer_del(eom_output->delay_timer); - eom_output->delay_timer = NULL; - - e_output_external_set(eom_output->eout, E_OUTPUT_DISPLAY_MODE_PRESENTATION); - - /* TODO: It works but maybe there is better solution exists ? - * Also I do not know how it affects on performance */ - if (ec->map_timer) - { - if (eom_trace_debug) - EOINF("delete map_timer", eom_output->eout); - E_FREE_FUNC(ec->map_timer, ecore_timer_del); - } - - if (eom_trace_debug) - EOINF("buffer_changed callback ec:%p, overlay:%d", eom_output->eout, ec, overlay); - - if (overlay) - { - Eina_Bool video_layer = EINA_FALSE; - tbm_format format; - Eina_Bool need_pp = EINA_FALSE; - - E_EomBufferPtr eom_buff = _e_eom_buffer_create(eom_output, wl_buffer); - EINA_SAFETY_ON_NULL_RETURN_VAL(eom_buff, ECORE_CALLBACK_PASS_ON); - - format = tbm_surface_get_format(tbm_buffer); - video_layer = _e_eom_output_video_layer_find(eom_output, format); - if (!video_layer) - { - /* need pp */ - need_pp = EINA_TRUE; - eom_output->need_overlay_pp = EINA_TRUE; - if (!_e_eom_pp_init(eom_output)) - { - EOERR("pp_init for overlay fail", eom_output->eout); - _e_eom_buffer_destroy(eom_output, eom_buff); - return ECORE_CALLBACK_PASS_ON; - } - } + /* get the output size */ + e_output_size_get(eom_output->output, &w, &h); + e_output_phys_size_get(eom_output->output, &pw, &ph); - if (eom_output->state != PRESENTATION) - { - _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_PRESENTATION); + wl_eom_send_output_info(resource, + eom_output->id, + eom_output->type, + e_output_display_mode_get(eom_output->output), + w, h, pw, ph, + eom_output->connection, + 1, 0, 0, 0); - EINA_LIST_FOREACH(g_eom->clients, l, eom_client_itr) - { - if (eom_client_itr->output_id == eom_output->id) - wl_eom_send_output_mode(eom_client_itr->resource, eom_output->id, - _e_eom_output_state_get_mode(eom_output)); - } + EOINF("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d", NULL, + eom_output->id, eom_output->type, e_output_display_mode_get(eom_output->output), + w, h, pw, ph, e_output_connected(eom_output->output)); +} - eom_output->state = PRESENTATION; - } +static const struct wl_eom_interface _e_eom_wl_implementation = +{ + _e_eom_cb_wl_request_set_attribute, + _e_eom_cb_wl_request_set_shell_window, + _e_eom_cb_wl_request_get_output_info +}; - if (need_pp) - { - if (eom_trace_debug) - EOINF("run _e_eom_presentation_pp_run", eom_output->eout); - _e_eom_presentation_pp_run(eom_output, tbm_buffer, eom_buff); - } - else - { - if (eom_trace_debug) - EOINF("run direct show", eom_output->eout); - _e_eom_layer_overlay_set(eom_output, tbm_buffer); +static void +_e_eom_cb_wl_eom_client_destroy(struct wl_resource *resource) +{ + E_EomClientPtr eom_client = NULL; + E_EomOutputPtr eom_output = NULL; + E_Output *primary_output = NULL; + E_Client *output_ec = NULL; - if (!_e_eom_output_show(eom_output, tbm_buffer, _e_eom_tbm_buffer_release_ext_mod, eom_buff)) - { - if (eom_trace_debug) - { - EOINF("===============> EXT ENDERR tbm_buff:%p", eom_output->eout, tbm_buffer); - EOINF("_e_eom_add_buff_to_show fail tbm_buff:%p", eom_output->eout, tbm_buffer); - } - _e_eom_buffer_destroy(eom_output, eom_buff); - return ECORE_CALLBACK_PASS_ON; - } - } - } - else - { - E_Plane *ep = NULL; + EOINF("=======================> CLIENT DESTROY", NULL); + + EINA_SAFETY_ON_NULL_RETURN(resource); - ep = e_output_default_fb_target_get(eom_output->eout); + eom_client = _e_eom_client_get_by_resource(resource); + EINA_SAFETY_ON_NULL_RETURN(eom_client); - if (ep->prepare_ec) - e_plane_ec_set(ep, ec); + g_eom->clients = eina_list_remove(g_eom->clients, eom_client); - if (eom_output->state != PRESENTATION) - { - _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_PRESENTATION); + eom_output = _e_eom_output_get_by_id(eom_client->output_id); + EINA_SAFETY_ON_NULL_GOTO(eom_output, end); - EINA_LIST_FOREACH(g_eom->clients, l, eom_client_itr) - { - if (eom_client_itr->output_id == eom_output->id) - wl_eom_send_output_mode(eom_client_itr->resource, eom_output->id, - _e_eom_output_state_get_mode(eom_output)); - } - eom_output->state = PRESENTATION; - } + output_ec = e_output_presentation_ec_get(eom_output->output); + if (eom_client->ec == output_ec) + { + _e_eom_output_attribute_set(eom_output, EOM_OUTPUT_ATTRIBUTE_NONE); + e_output_presentation_unset(eom_output->output); - e_comp_object_hwc_update_set(ec->frame, EINA_TRUE); + primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen); + if (!e_output_mirror_set(eom_output->output, primary_output)) + EOERR("e_output_mirror_set fails", eom_output->output); } - if (eom_trace_debug) - EOINF("===============< EXT START", eom_output->eout); +end: + /* Notify eom clients which are binded to a concrete output that the + * state and mode of the output has been changed */ + if (eom_output) + _e_eom_output_status_broadcast(eom_output, eom_client, EOM_OUTPUT_ATTRIBUTE_STATE_NONE); - return ECORE_CALLBACK_PASS_ON; + free(eom_client); } -static Eina_Bool -_e_eom_connect(E_Output *output) +static void +_e_eom_cb_wl_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { + struct wl_resource *resource = NULL; + E_EomPtr eom = NULL; + E_EomClientPtr eom_client = NULL; E_EomOutputPtr eom_output = NULL; + Eina_List *l; + int w, h, pw, ph; - if (!g_eom) return EINA_TRUE; - - g_eom->check_first_boot = 1; + EINA_SAFETY_ON_NULL_RETURN(data); + eom = data; - eom_output = _e_eom_output_find(output); - if (eom_output == NULL) + resource = wl_resource_create(client, &wl_eom_interface, MIN(version, 1), id); + if (resource == NULL) { - eom_output = _e_eom_output_find_added_output(output); - if (!eom_output) - { - EOERR("cannot find eom_output", NULL); - return EINA_FALSE; - } + EOERR("resource is null. (version :%d, id:%d)", NULL, version, id); + wl_client_post_no_memory(client); + return; } - if (eom_output->connection_status == EINA_TRUE) - return EINA_TRUE; - - /* update eom_output connect */ - eom_output->width = output->config.mode.w; - eom_output->height = output->config.mode.h; - eom_output->phys_width = output->info.size.w; - eom_output->phys_height = output->info.size.h; - eom_output->name = eina_stringshare_add(output->id); - eom_output->connection_status = EINA_TRUE; + wl_resource_set_implementation(resource, &_e_eom_wl_implementation, eom, _e_eom_cb_wl_eom_client_destroy); - EOINF("Setup new eom_output: (%dx%d)", eom_output->eout, eom_output->width, eom_output->height); + wl_eom_send_output_count(resource, g_eom->eom_output_count); - /* TODO: check eom_output mode(presentation set) and HDMI type */ - if (eom_output->state == WAIT_PRESENTATION) + EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) { - EOINF("Start wait Presentation", eom_output->eout); + if (!eom_output) continue; - _e_eom_send_configure_event(); + /* get the output size */ + e_output_size_get(eom_output->output, &w, &h); + e_output_phys_size_get(eom_output->output, &pw, &ph); - if (eom_output->delay_timer) - ecore_timer_del(eom_output->delay_timer); - eom_output->delay_timer = ecore_timer_add(EOM_DELAY_CONNECT_CHECK_TIMEOUT, _e_eom_presentation_check, eom_output); - } - else - { - EOINF("Start Mirroring", eom_output->eout); - _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_MIRROR); - eom_output->state = MIRROR; - e_output_external_set(output, E_OUTPUT_DISPLAY_MODE_MIRROR); + wl_eom_send_output_info(resource, + eom_output->id, + eom_output->type, + e_output_display_mode_get(eom_output->output), + w, h, pw, ph, + eom_output->connection, + 1, 0, 0, 0); + + EOINF("send - id : %d, type : %d, mode : %d, w : %d, h : %d, w_mm : %d, h_mm : %d, conn : %d", eom_output->output, + eom_output->id, eom_output->type, e_output_display_mode_get(eom_output->output), + w, h, pw, ph, e_output_connected(eom_output->output)); } - eom_output->connection = WL_EOM_STATUS_CONNECTION; + eom_client = E_NEW(E_EomClient, 1); + EINA_SAFETY_ON_NULL_RETURN(eom_client); - /* If there were previously connected clients to the output - notify them */ - _e_eom_output_info_broadcast(eom_output, EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE); + eom_client->resource = resource; + eom_client->current = EINA_FALSE; + eom_client->output_id = -1; + eom_client->ec = NULL; - return EINA_TRUE; + g_eom->clients = eina_list_append(g_eom->clients, eom_client); + + EOINF("=======================> BIND CLIENT", NULL); } static Eina_Bool -_e_eom_disconnect(E_Output *output) +_e_eom_connect(E_Output *output) { E_EomOutputPtr eom_output = NULL; + E_Client *ec = NULL; + int w, h; if (!g_eom) return EINA_TRUE; - g_eom->check_first_boot = 1; - eom_output = _e_eom_output_find(output); - if (eom_output == NULL) + if (!eom_output) { - eom_output = _e_eom_output_find_added_output(output); - if (!eom_output) - { - EOERR("cannot find output", NULL); - return EINA_FALSE; - } + EOERR("cannot find eom_output", NULL); + return EINA_FALSE; } - if (eom_output->connection_status == EINA_FALSE) - return EINA_TRUE; - - if (eom_output->delay_timer) - ecore_timer_del(eom_output->delay_timer); - eom_output->delay_timer = NULL; - - /* update eom_output disconnect */ - eom_output->width = 0; - eom_output->height = 0; - eom_output->phys_width = 0; - eom_output->phys_height = 0; - eom_output->connection = WL_EOM_STATUS_DISCONNECTION; - - e_output_external_unset(output); + if (e_output_display_mode_get(eom_output->output) == E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION) + { + EOINF("Send Configure Event for Presentation", eom_output->output); - eom_output->connection_status = EINA_FALSE; + ec = e_output_presentation_ec_get(eom_output->output); + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); - _e_eom_output_state_set_mode(eom_output, EOM_OUTPUT_MODE_NONE); + _e_eom_output_send_configure_event(eom_output, ec); + } - if (_e_eom_client_get_current_by_id(eom_output->id)) - eom_output->state = WAIT_PRESENTATION; - else - eom_output->state = NONE; + eom_output->connection = WL_EOM_STATUS_CONNECTION; /* If there were previously connected clients to the output - notify them */ - _e_eom_output_info_broadcast(eom_output, EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE); + _e_eom_output_info_broadcast(eom_output, EOM_OUTPUT_ATTRIBUTE_STATE_ACTIVE); - EOINF("Destory output: %s", eom_output->eout, eom_output->name); - eina_stringshare_del(eom_output->name); - eom_output->name = NULL; + /* get the output size */ + e_output_size_get(eom_output->output, &w, &h); + EOINF("Setup new eom_output: (%dx%d)", eom_output->output, w, h); return EINA_TRUE; } static Eina_Bool -_e_eom_mode_change(E_Output *output, E_Output_Mode *emode) +_e_eom_disconnect(E_Output *output) { E_EomOutputPtr eom_output = NULL; - E_Output *output_primary = NULL; if (!g_eom) return EINA_TRUE; - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - - output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen); - EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL(output_primary == output, EINA_FALSE); - eom_output = _e_eom_output_find(output); - if (eom_output == NULL) + if (!eom_output) { - eom_output = _e_eom_output_find_added_output(output); - if (!eom_output) - { - EOERR("cannot find output", NULL); - return EINA_FALSE; - } + EOERR("cannot find output", NULL); + return EINA_FALSE; } - if (eom_output->connection_status == EINA_FALSE) - return EINA_FALSE; - - if (eom_output->delay_timer) - ecore_timer_del(eom_output->delay_timer); - eom_output->delay_timer = NULL; - - /* update eom_output connect */ - eom_output->width = output->config.mode.w; - eom_output->height = output->config.mode.h; - eom_output->phys_width = output->info.size.w; - eom_output->phys_height = output->info.size.h; - eom_output->name = eina_stringshare_add(output->id); - eom_output->connection_status = EINA_TRUE; + /* update eom_output disconnect */ + eom_output->connection = WL_EOM_STATUS_DISCONNECTION; - EOINF("mode change output: (%dx%d)", eom_output->eout, eom_output->width, eom_output->height); - if (eom_output->state == PRESENTATION) - { - eom_output->state = WAIT_PRESENTATION; - _e_eom_send_configure_event(); + /* If there were previously connected clients to the output - notify them */ + _e_eom_output_info_broadcast(eom_output, EOM_OUTPUT_ATTRIBUTE_STATE_INACTIVE); - eom_output->delay_timer = ecore_timer_add(EOM_DELAY_CONNECT_CHECK_TIMEOUT, _e_eom_presentation_check, eom_output); - } + EOINF("Destory output.", eom_output->output); return EINA_TRUE; } @@ -2334,130 +904,109 @@ _e_eom_mode_change(E_Output *output, E_Output_Mode *emode) static void _e_eom_output_cb_output_connect_status_change(void *data, E_Output *output) { - EINA_SAFETY_ON_NULL_RETURN(g_eom->output_primary); - - /* doesn't care about the pirmary output */ - if (g_eom->output_primary == output) return; - if (e_output_connected(output)) - { - _e_eom_connect(output); - } + _e_eom_connect(output); else - { - _e_eom_disconnect(output); - } + _e_eom_disconnect(output); } static void _e_eom_output_cb_output_mode_change(void *data, E_Output *output) { - E_Output_Mode *emode; - - EINA_SAFETY_ON_NULL_RETURN(g_eom->output_primary); - - /* doesn't care about the pirmary output */ - if (g_eom->output_primary == output) return; + E_EomOutputPtr eom_output = NULL; + E_Client *ec = NULL; - if (!e_output_connected(output)) + /* if presentation, send configure notify to all eom_clients */ + if (e_output_display_mode_get(output) == E_OUTPUT_DISPLAY_MODE_PRESENTATION) { - EOERR("output is disconnected.", output); - return; - } + eom_output = _e_eom_output_find(output); + EINA_SAFETY_ON_NULL_RETURN(eom_output); - emode = e_output_current_mode_get(output); - EINA_SAFETY_ON_FALSE_RETURN(emode); + ec = e_output_presentation_ec_get(output); + EINA_SAFETY_ON_NULL_RETURN(ec); - if (!_e_eom_mode_change(output, emode)) - { - EOERR("_e_eom_mode_change fails.", output); - return; + _e_eom_output_send_configure_event(eom_output, ec); } } static void _e_eom_output_cb_output_add(void *data, E_Output *output) { - EINA_SAFETY_ON_NULL_RETURN(g_eom->output_primary); - - /* doesn't care about the pirmary output */ - if (g_eom->output_primary == output) return; - - if (!_e_eom_create(output, EINA_TRUE)) + if (!_e_eom_output_create(output, EINA_TRUE)) { - EOERR("_e_eom_create fails.", output); + EOERR("_e_eom_output_create fails.", output); return; } } static void -_e_eom_output_cb_output_remove(void *data, E_Output *output) +_e_eom_output_cb_output_del(void *data, E_Output *output) { - EINA_SAFETY_ON_NULL_RETURN(g_eom->output_primary); - - /* doesn't care about the pirmary output */ - if (g_eom->output_primary == output) return; - - if (!_e_eom_destroy(output)) + if (!_e_eom_output_destroy(output)) { - EOERR("_e_eom_destroy fails.", output); + EOERR("_e_eom_output_destroy fails.", output); return; } } static void -_e_eom_deinit() +_e_eom_output_deinit(void) { - Ecore_Event_Handler *h = NULL; + E_EomOutputPtr eom_output; + Eina_List *l; - if (g_eom == NULL) return; + if (!g_eom) return; + if (!g_eom->eom_outputs) return; - if (g_eom->output_remove_hook) - { - e_output_hook_del(g_eom->output_remove_hook); - g_eom->output_remove_hook = NULL; - } + EINA_LIST_FOREACH(g_eom->eom_outputs, l, eom_output) + _e_eom_output_destroy(eom_output->output); - if (g_eom->output_add_hook) - { - e_output_hook_del(g_eom->output_add_hook); - g_eom->output_add_hook = NULL; - } + eina_list_free(g_eom->eom_outputs); + g_eom->eom_outputs = NULL; +} - if (g_eom->output_mode_changes_hook) - { - e_output_hook_del(g_eom->output_mode_changes_hook); - g_eom->output_mode_changes_hook = NULL; - } +static Eina_Bool +_e_eom_output_init(void) +{ + E_Comp_Screen *e_comp_screen = NULL; + E_Output *output = NULL; + E_Output *primary_output = NULL; + Eina_List *l; - if (g_eom->output_connect_status_hook) - { - e_output_hook_del(g_eom->output_connect_status_hook); - g_eom->output_connect_status_hook = NULL; - } + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE); - if (g_eom->handlers) + e_comp_screen = e_comp->e_comp_screen; + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE); + + primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen); + EINA_SAFETY_ON_NULL_RETURN_VAL(primary_output, EINA_FALSE); + + g_eom->eom_output_count = e_comp_screen->num_outputs - 1; + EOINF("external output count : %d", NULL, g_eom->eom_output_count); + + /* create the eom_output except for the primary output */ + EINA_LIST_FOREACH(e_comp_screen->outputs, l, output) { - EINA_LIST_FREE(g_eom->handlers, h) - ecore_event_handler_del(h); + if (!output) continue; + if (output == primary_output) continue; - g_eom->handlers = NULL; + if (!_e_eom_output_create(output, EINA_FALSE)) + { + EOERR("_e_eom_output_create fails.", output); + goto err; + } } - _e_eom_output_deinit(); - - if (g_eom->dpy) - g_eom->dpy = NULL; + return EINA_TRUE; - if (g_eom->global) - wl_global_destroy(g_eom->global); - g_eom->global = NULL; +err: + _e_eom_output_deinit(); - E_FREE(g_eom); + return EINA_FALSE; } -static Eina_Bool -_e_eom_init() +EINTERN Eina_Bool +e_eom_init(void) { EINA_SAFETY_ON_NULL_GOTO(e_comp_wl, err); @@ -2470,54 +1019,72 @@ _e_eom_init() g_eom->global = wl_global_create(e_comp_wl->wl.disp, &wl_eom_interface, 1, g_eom, _e_eom_cb_wl_bind); EINA_SAFETY_ON_NULL_GOTO(g_eom->global, err); - g_eom->dpy = e_comp->e_comp_screen->tdisplay; - EINA_SAFETY_ON_NULL_GOTO(g_eom->dpy, err); - - g_eom->output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen); - EINA_SAFETY_ON_NULL_GOTO(g_eom->output_primary, err); - if (!_e_eom_output_init()) { EOERR("_e_eom_output_init fail", NULL); goto err; } - g_eom->timer = ecore_timer_add(EOM_CONNECT_CHECK_TIMEOUT, _e_eom_boot_connection_check, NULL); - - E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, NULL); - g_eom->output_connect_status_hook = e_output_hook_add(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, _e_eom_output_cb_output_connect_status_change, g_eom); g_eom->output_mode_changes_hook = e_output_hook_add(E_OUTPUT_HOOK_MODE_CHANGE, _e_eom_output_cb_output_mode_change, g_eom); g_eom->output_add_hook = e_output_hook_add(E_OUTPUT_HOOK_ADD, _e_eom_output_cb_output_add, g_eom); - g_eom->output_remove_hook = e_output_hook_add(E_OUTPUT_HOOK_REMOVE, _e_eom_output_cb_output_remove, g_eom); + g_eom->output_remove_hook = e_output_hook_add(E_OUTPUT_HOOK_REMOVE, _e_eom_output_cb_output_del, g_eom); + + E_LIST_HANDLER_APPEND(g_eom->handlers, E_EVENT_CLIENT_BUFFER_CHANGE, _e_eom_cb_client_buffer_change, g_eom); return EINA_TRUE; err: - _e_eom_deinit(); + e_eom_shutdown(); return EINA_FALSE; } EINTERN int -e_eom_init(void) +e_eom_shutdown(void) { - Eina_Bool ret = EINA_FALSE; + Ecore_Event_Handler *h = NULL; - ret = _e_eom_init(); + if (!g_eom) return 1; - if (ret == EINA_FALSE) - return 0; + if (g_eom->handlers) + { + EINA_LIST_FREE(g_eom->handlers, h) + ecore_event_handler_del(h); + g_eom->handlers = NULL; + } - return 1; -} + if (g_eom->output_remove_hook) + { + e_output_hook_del(g_eom->output_remove_hook); + g_eom->output_remove_hook = NULL; + } -EINTERN int -e_eom_shutdown(void) -{ - if (!g_eom) return 1; + if (g_eom->output_add_hook) + { + e_output_hook_del(g_eom->output_add_hook); + g_eom->output_add_hook = NULL; + } + + if (g_eom->output_mode_changes_hook) + { + e_output_hook_del(g_eom->output_mode_changes_hook); + g_eom->output_mode_changes_hook = NULL; + } + + if (g_eom->output_connect_status_hook) + { + e_output_hook_del(g_eom->output_connect_status_hook); + g_eom->output_connect_status_hook = NULL; + } - _e_eom_deinit(); + _e_eom_output_deinit(); + + if (g_eom->global) + wl_global_destroy(g_eom->global); + g_eom->global = NULL; + + E_FREE(g_eom); return 1; } @@ -2530,8 +1097,7 @@ e_eom_is_ec_external(E_Client *ec) if (!g_eom) return EINA_FALSE; eom_output = _e_eom_output_by_ec_child_get(ec); - if (!eom_output) - return EINA_FALSE; + if (!eom_output) return EINA_FALSE; return EINA_TRUE; } \ No newline at end of file diff --git a/src/bin/e_eom.h b/src/bin/e_eom.h index 0f5761d..a813851 100644 --- a/src/bin/e_eom.h +++ b/src/bin/e_eom.h @@ -4,10 +4,8 @@ #ifndef E_COMP_WL_EOM_H #define E_COMP_WL_EOM_H -#include - -EINTERN int e_eom_init(void); -EINTERN int e_eom_shutdown(void); +EINTERN Eina_Bool e_eom_init(void); +EINTERN int e_eom_shutdown(void); E_API Eina_Bool e_eom_is_ec_external(E_Client *ec); diff --git a/src/bin/e_hwc.h b/src/bin/e_hwc.h index 11f95bb..37fe385 100644 --- a/src/bin/e_hwc.h +++ b/src/bin/e_hwc.h @@ -121,8 +121,10 @@ struct _E_Hwc /* external output */ Eina_Rectangle mirror_rect; E_Hwc *mirror_src_hwc; + tbm_surface_h mirror_src_tsurface; Eina_List *mirror_dst_hwc; - E_Output_Display_Mode display_mode; + tbm_surface_h presentation_tsurface; + E_Hwc_Window *presentation_hwc_window; int norender; diff --git a/src/bin/e_hwc_planes.c b/src/bin/e_hwc_planes.c index 1e91ed3..8da83ff 100644 --- a/src/bin/e_hwc_planes.c +++ b/src/bin/e_hwc_planes.c @@ -759,3 +759,179 @@ e_hwc_planes_apply(E_Hwc *hwc) else _e_hwc_planes_changed(hwc); } + +EINTERN Eina_Bool +e_hwc_planes_mirror_set(E_Hwc *hwc, E_Hwc *src_hwc, Eina_Rectangle *rect) +{ + E_Output *output, *src_output; + E_Plane *ep; + + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(src_hwc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(rect, EINA_FALSE); + + ELOGF("HWC-PLNS", "e_hwc_planes_mirror_set. rect(%d,%d)(%d,%d)", NULL, + rect->x, rect->y, rect->w, rect->h); + + output = hwc->output; + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + + src_output = src_hwc->output; + EINA_SAFETY_ON_NULL_RETURN_VAL(src_output, EINA_FALSE); + + ep = e_output_fb_target_get(output); + EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE); + + ep->output_primary = src_output; + if (!e_plane_external_set(ep, rect, E_OUTPUT_DISPLAY_MODE_MIRROR)) + { + ERR("e_plane_mirror_set failed."); + return EINA_FALSE; + } + + /* add mirror_src to the hwc*/ + hwc->mirror_src_hwc = src_hwc; + + /* add mirror_dst list to the src_hwc */ + src_hwc->mirror_dst_hwc = eina_list_append(src_hwc->mirror_dst_hwc, hwc); + + /* make the src_hwc be full gl-compositing */ + e_hwc_deactive_set(src_hwc, EINA_TRUE); + //e_comp_hwc_multi_plane_set(EINA_FALSE); + + return EINA_TRUE; +} + +EINTERN void +e_hwc_planes_mirror_unset(E_Hwc *hwc) +{ + E_Output *output; + E_Hwc *src_hwc; + E_Plane *ep = NULL; + + EINA_SAFETY_ON_NULL_RETURN(hwc); + + output = hwc->output; + EINA_SAFETY_ON_NULL_RETURN(output); + + src_hwc = hwc->mirror_src_hwc; + EINA_SAFETY_ON_NULL_RETURN(src_hwc); + + ep = e_output_fb_target_get(output); + EINA_SAFETY_ON_NULL_RETURN(ep); + + e_plane_external_unset(ep); + + /* remove mirror_dst list at the src_hwc */ + src_hwc->mirror_dst_hwc = eina_list_remove(src_hwc->mirror_dst_hwc, hwc); + + /* remove mirror_src at the hwc */ + hwc->mirror_src_hwc = NULL; + + e_hwc_deactive_set(src_hwc, EINA_FALSE); + //e_comp_hwc_multi_plane_set(EINA_TRUEE); + + ELOGF("HWC-PLNS", "e_hwc_planes_mirror_unset", NULL); +} + +EINTERN Eina_Bool +e_hwc_planes_presentation_update(E_Hwc *hwc, E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + +#if 0 + if (overlay) + { + Eina_Bool video_layer = EINA_FALSE; + tbm_format format; + Eina_Bool need_pp = EINA_FALSE; + + E_EomBufferPtr eom_buff = _e_eom_buffer_create(eom_output, wl_buffer); + EINA_SAFETY_ON_NULL_RETURN_VAL(eom_buff, ECORE_CALLBACK_PASS_ON); + + format = tbm_surface_get_format(tbm_buffer); + video_layer = _e_eom_output_video_layer_find(eom_output, format); + if (!video_layer) + { + /* need pp */ + need_pp = EINA_TRUE; + eom_output->need_overlay_pp = EINA_TRUE; + if (!_e_eom_pp_init(eom_output)) + { + EOERR("pp_init for overlay fail", eom_output->eout); + _e_eom_buffer_destroy(eom_output, eom_buff); + return ECORE_CALLBACK_PASS_ON; + } + } + + if (need_pp) + { + if (eom_trace_debug) + EOINF("run _e_eom_presentation_pp_run", eom_output->eout); + _e_eom_presentation_pp_run(eom_output, tbm_buffer, eom_buff); + } + else + { + if (eom_trace_debug) + EOINF("run direct show", eom_output->eout); + _e_eom_layer_overlay_set(eom_output, tbm_buffer); + + if (!_e_eom_output_show(eom_output, tbm_buffer, _e_eom_tbm_buffer_release_ext_mod, eom_buff)) + { + if (eom_trace_debug) + { + EOINF("===============> EXT ENDERR tbm_buff:%p", eom_output->eout, tbm_buffer); + EOINF("_e_eom_add_buff_to_show fail tbm_buff:%p", eom_output->eout, tbm_buffer); + } + _e_eom_buffer_destroy(eom_output, eom_buff); + return ECORE_CALLBACK_PASS_ON; + } + } + } + else + { + E_Plane *ep = NULL; + + ep = e_output_default_fb_target_get(eom_output->eout); + + if (ep->prepare_ec) + e_plane_ec_set(ep, ec); + + e_comp_object_hwc_update_set(ec->frame, EINA_TRUE); + } +#endif + + return EINA_TRUE; +} + +EINTERN Eina_Bool +e_hwc_planes_external_commit(E_Hwc *hwc) +{ + E_Output *output; + E_Plane *plane = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); + + output = hwc->output; + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc->output, EINA_FALSE); + + /* external commit only primary */ + plane = e_output_fb_target_get(output); + + /* external commit */ + if (e_output_dpms_get(output)) + return EINA_TRUE; + + if (!e_plane_external_fetch(plane)) + return EINA_TRUE; + + if (!e_plane_external_commit(plane)) + { + ERR("fail to e_plane_ex_commit"); + return EINA_FALSE; + } + + return EINA_TRUE; +} + diff --git a/src/bin/e_hwc_planes.h b/src/bin/e_hwc_planes.h index 11217d2..7546908 100644 --- a/src/bin/e_hwc_planes.h +++ b/src/bin/e_hwc_planes.h @@ -14,5 +14,10 @@ EINTERN void e_hwc_planes_apply(E_Hwc *hwc); EINTERN void e_hwc_planes_multi_plane_set(E_Hwc *hwc, Eina_Bool set); EINTERN Eina_Bool e_hwc_planes_multi_plane_get(E_Hwc *hwc); +EINTERN Eina_Bool e_hwc_planes_mirror_set(E_Hwc *hwc, E_Hwc *src_hwc, Eina_Rectangle *rect); +EINTERN void e_hwc_planes_mirror_unset(E_Hwc *hwc); +EINTERN Eina_Bool e_hwc_planes_presentation_update(E_Hwc *hwc, E_Client *ec); +EINTERN Eina_Bool e_hwc_planes_external_commit(E_Hwc *hwc); + #endif #endif diff --git a/src/bin/e_hwc_windows.c b/src/bin/e_hwc_windows.c index 1e63621..95ede75 100644 --- a/src/bin/e_hwc_windows.c +++ b/src/bin/e_hwc_windows.c @@ -2,7 +2,9 @@ #include "services/e_service_quickpanel.h" # include # include +# include # include +# include #define DBG_EVALUATE 1 @@ -902,6 +904,7 @@ _e_hwc_windows_target_window_new(E_Hwc *hwc) !strcmp("gl_tbm_ES", name)) { ecore_evas_manual_render_set(hwc->ee, 1); + ecore_evas_show(hwc->ee); } target_hwc_window = E_OBJECT_ALLOC(E_Hwc_Window_Target, E_HWC_WINDOW_TYPE, _e_hwc_windows_target_window_free); @@ -2548,37 +2551,44 @@ e_hwc_windows_zoom_set(E_Hwc *hwc, Eina_Rectangle *rect) EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); - if ((hwc->pp_rect.x == rect->x) && - (hwc->pp_rect.y == rect->y) && - (hwc->pp_rect.w == rect->w) && - (hwc->pp_rect.h == rect->h)) + if ((hwc->pp_rect.x == rect->x) && (hwc->pp_rect.y == rect->y) && + (hwc->pp_rect.w == rect->w) && (hwc->pp_rect.h == rect->h)) return EINA_TRUE; e_comp_screen = e_comp->e_comp_screen; e_output_size_get(hwc->output, &w, &h); - if (!hwc->tpp) + if (e_comp_screen_pp_support()) { - hwc->tpp = tdm_display_create_pp(e_comp_screen->tdisplay, &ret); - if (ret != TDM_ERROR_NONE) + if (!hwc->tpp) { - EHWSERR("fail tdm pp create", hwc); - goto fail; - } + hwc->tpp = tdm_display_create_pp(e_comp_screen->tdisplay, &ret); + if (ret != TDM_ERROR_NONE) + { + EHWSERR("fail tdm pp create", hwc); + goto fail; + } - ret = tdm_pp_set_done_handler(hwc->tpp, _e_hwc_windows_pp_commit_handler, hwc); - EINA_SAFETY_ON_FALSE_GOTO(ret == TDM_ERROR_NONE, fail); - } + ret = tdm_pp_set_done_handler(hwc->tpp, _e_hwc_windows_pp_commit_handler, hwc); + EINA_SAFETY_ON_FALSE_GOTO(ret == TDM_ERROR_NONE, fail); + } - if (!hwc->pp_tqueue) - { - //TODO: Does e20 get the buffer flags from the tdm backend? - hwc->pp_tqueue = tbm_surface_queue_create(3, w, h, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); if (!hwc->pp_tqueue) { - EHWSERR("fail tbm_surface_queue_create", hwc); - goto fail; + //TODO: Does e20 get the buffer flags from the tdm backend? + hwc->pp_tqueue = tbm_surface_queue_create(3, w, h, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); + if (!hwc->pp_tqueue) + { + EHWSERR("fail tbm_surface_queue_create", hwc); + goto fail; + } } + + hwc->pp_set = EINA_TRUE; + hwc->pp_set_info = EINA_TRUE; + hwc->pp_unset = EINA_FALSE; + hwc->pp_hwc_window = NULL; + hwc->target_hwc_window->skip_surface_set = EINA_TRUE; } hwc->pp_rect.x = rect->x; @@ -2586,12 +2596,6 @@ e_hwc_windows_zoom_set(E_Hwc *hwc, Eina_Rectangle *rect) hwc->pp_rect.w = rect->w; hwc->pp_rect.h = rect->h; - hwc->pp_set = EINA_TRUE; - hwc->target_hwc_window->skip_surface_set = EINA_TRUE; - hwc->pp_set_info = EINA_TRUE; - hwc->pp_unset = EINA_FALSE; - hwc->pp_hwc_window = NULL; - /* to wake up main loop */ uint64_t value = 1; if (write(hwc->target_hwc_window->event_fd, &value, sizeof(value)) < 0) @@ -2614,39 +2618,42 @@ e_hwc_windows_zoom_unset(E_Hwc *hwc) { EINA_SAFETY_ON_NULL_RETURN(hwc); - hwc->pp_set_info = EINA_FALSE; - hwc->target_hwc_window->skip_surface_set = EINA_FALSE; - hwc->pp_set = EINA_FALSE; - hwc->pp_hwc_window = NULL; - hwc->pp_unset = EINA_TRUE; - hwc->pp_rect.x = 0; hwc->pp_rect.y = 0; hwc->pp_rect.w = 0; hwc->pp_rect.h = 0; - _e_hwc_windows_pp_pending_data_remove(hwc); + if (e_comp_screen_pp_support()) + { + hwc->target_hwc_window->skip_surface_set = EINA_FALSE; + hwc->pp_set_info = EINA_FALSE; + hwc->pp_set = EINA_FALSE; + hwc->pp_hwc_window = NULL; + hwc->pp_unset = EINA_TRUE; - if (hwc->pp_tsurface) - tbm_surface_queue_release(hwc->pp_tqueue, hwc->pp_tsurface); + _e_hwc_windows_pp_pending_data_remove(hwc); - if (hwc->pp_tqueue) - { - tbm_surface_queue_destroy(hwc->pp_tqueue); - hwc->pp_tqueue = NULL; - } + if (hwc->pp_tsurface) + tbm_surface_queue_release(hwc->pp_tqueue, hwc->pp_tsurface); - if (!hwc->pp_commit) - { - if (hwc->tpp) + if (hwc->pp_tqueue) { - tdm_pp_destroy(hwc->tpp); - hwc->tpp = NULL; + tbm_surface_queue_destroy(hwc->pp_tqueue); + hwc->pp_tqueue = NULL; } - } - if (hwc->pp_output_commit_data) - hwc->wait_commit = EINA_TRUE; + if (!hwc->pp_commit) + { + if (hwc->tpp) + { + tdm_pp_destroy(hwc->tpp); + hwc->tpp = NULL; + } + } + + if (hwc->pp_output_commit_data) + hwc->wait_commit = EINA_TRUE; + } /* to wake up main loop */ uint64_t value = 1; @@ -2903,14 +2910,20 @@ EINTERN Eina_Bool e_hwc_windows_mirror_set(E_Hwc *hwc, E_Hwc *src_hwc, Eina_Rectangle *rect) { EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(src_hwc, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(rect, EINA_FALSE); - EHWSTRACE("e_hwc_windows_mirror_set. rect(%d,%d)(%d,%d)", - NULL, hwc, rect->x, rect->y, rect->w, rect->h); + EHWSINF("e_hwc_windows_mirror_set. rect(%d,%d)(%d,%d)", + NULL, hwc, rect->x, rect->y, rect->w, rect->h); - hwc->mirror_rect.x = rect->x; - hwc->mirror_rect.y = rect->y; - hwc->mirror_rect.w = rect->w; - hwc->mirror_rect.h = rect->h; + hwc->mirror_src_tsurface = NULL; + + /* set the zoom to the hwc. */ + if (!e_hwc_windows_zoom_set(hwc, rect)) + { + EHWSERR("e_hwc_windows_zoom_set failed.", hwc); + return EINA_FALSE; + } /* add mirror_src to the hwc*/ hwc->mirror_src_hwc = src_hwc; @@ -2918,8 +2931,6 @@ e_hwc_windows_mirror_set(E_Hwc *hwc, E_Hwc *src_hwc, Eina_Rectangle *rect) /* add mirror_dst list to the src_hwc */ src_hwc->mirror_dst_hwc = eina_list_append(src_hwc->mirror_dst_hwc, hwc); - hwc->display_mode = E_OUTPUT_DISPLAY_MODE_MIRROR; - /* make the src_hwc be full gl-compositing */ e_hwc_deactive_set(src_hwc, EINA_TRUE); @@ -2938,7 +2949,8 @@ e_hwc_windows_mirror_unset(E_Hwc *hwc) e_hwc_deactive_set(src_hwc, EINA_FALSE); - hwc->display_mode = E_OUTPUT_DISPLAY_MODE_NONE; + /* unset the zoom. */ + e_hwc_windows_zoom_unset(hwc); /* remove mirror_dst list at the src_hwc */ src_hwc->mirror_dst_hwc = eina_list_remove(src_hwc->mirror_dst_hwc, hwc); @@ -2946,10 +2958,338 @@ e_hwc_windows_mirror_unset(E_Hwc *hwc) /* remove mirror_src at the hwc */ hwc->mirror_src_hwc = NULL; - hwc->mirror_rect.x = 0; - hwc->mirror_rect.y = 0; - hwc->mirror_rect.w = 0; - hwc->mirror_rect.h = 0; + hwc->mirror_src_tsurface = NULL; + + EHWSINF("e_hwc_windows_mirror_unset", NULL, hwc); +} + +EINTERN Eina_Bool +e_hwc_windows_presentation_update(E_Hwc *hwc, E_Client *ec) +{ + E_Comp_Wl_Buffer *wl_buffer = NULL; + tbm_surface_h tsurface = NULL; + E_Hwc_Window *hwc_window = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); + + if (ec) + { + if (!hwc->presentation_hwc_window) + { + /* create the hwc_window on the external hwc. */ + hwc->presentation_hwc_window = e_hwc_window_new(hwc, ec, E_HWC_WINDOW_STATE_DEVICE); + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE); + // TODO: deal with the video + } + + /* update the target_buffer */ + wl_buffer = e_pixmap_resource_get(ec->pixmap); + EINA_SAFETY_ON_NULL_RETURN_VAL(wl_buffer, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(wl_buffer->resource, EINA_FALSE); + + tsurface = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, wl_buffer->resource); + EINA_SAFETY_ON_NULL_RETURN_VAL(tsurface, EINA_FALSE); + + hwc->presentation_tsurface = tsurface; + } + else + { + hwc->presentation_tsurface = NULL; + + if (hwc->presentation_hwc_window) + { + e_hwc_window_free(hwc_window); + hwc->presentation_hwc_window = NULL; + } + } + + return EINA_TRUE; +} + +static void +_e_hwc_windows_pixman_copy(E_Hwc *hwc, tbm_surface_h src_tsurface, tbm_surface_h dst_tsurface) +{ + pixman_image_t *src_img = NULL, *dst_img = NULL; + pixman_format_code_t src_format, dst_format; + double scale_x, scale_y; + pixman_transform_t t; + struct pixman_f_transform ft; + tbm_surface_info_s src_tinfo = {0}; + tbm_surface_info_s dst_tinfo = {0}; + int ret = TBM_SURFACE_ERROR_NONE; + + ret = tbm_surface_map(src_tsurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &src_tinfo); + if (ret != TBM_SURFACE_ERROR_NONE) + { + EHWSERR("tbm_surface_map fails on src_tsurface.", hwc); + goto end; + } + + ret = tbm_surface_map(dst_tsurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &dst_tinfo); + if (ret != TBM_SURFACE_ERROR_NONE) + { + EHWSERR("tbm_surface_map fails on dst_tsurface.", hwc); + goto src_unmap; + } + + src_format = PIXMAN_a8r8g8b8; + dst_format = PIXMAN_a8r8g8b8; + + src_img = pixman_image_create_bits(src_format, src_tinfo.width, src_tinfo.height, + (uint32_t*)src_tinfo.planes[0].ptr, + src_tinfo.planes[0].stride); + EINA_SAFETY_ON_NULL_GOTO(src_img, free_img); + + dst_img = pixman_image_create_bits(dst_format, dst_tinfo.width, dst_tinfo.height, + (uint32_t*)dst_tinfo.planes[0].ptr, + dst_tinfo.planes[0].stride); + EINA_SAFETY_ON_NULL_GOTO(dst_img, free_img); + + if (dst_tinfo.width > 0) + scale_x = (double)src_tinfo.width / dst_tinfo.width; + else + scale_x = (double)src_tinfo.width; + + if (dst_tinfo.height > 0) + scale_y = (double)src_tinfo.height / dst_tinfo.height; + else + scale_y = (double)src_tinfo.height; + + pixman_f_transform_init_identity(&ft); + + pixman_f_transform_scale(&ft, NULL, scale_x, scale_y); + pixman_f_transform_translate(&ft, NULL, 0, 0); + pixman_transform_from_pixman_f_transform(&t, &ft); + pixman_image_set_transform(src_img, &t); + + pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img, 0, 0, 0, 0, + 0, 0, dst_tinfo.width, dst_tinfo.height); + +free_img: + if (src_img) pixman_image_unref(src_img); + if (dst_img) pixman_image_unref(dst_img); + + tbm_surface_unmap(dst_tsurface); +src_unmap: + tbm_surface_unmap(src_tsurface); +end: + return; +} + +static Eina_Bool +_e_hwc_windows_mirror_changes_update(E_Hwc *hwc) +{ + E_Hwc *mirror_src_hwc; + E_Hwc_Window_Target *target_hwc_window, *src_target_hwc_window; + tbm_surface_h target_tsurface, src_target_tsurface; + E_Hwc_Window_Queue *queue; + E_Hwc_Window_Queue_Buffer *queue_buffer = NULL; + + mirror_src_hwc = hwc->mirror_src_hwc; + EINA_SAFETY_ON_NULL_RETURN_VAL(mirror_src_hwc, EINA_FALSE); + + target_hwc_window = hwc->target_hwc_window; + EINA_SAFETY_ON_NULL_RETURN_VAL(target_hwc_window, EINA_FALSE); + + src_target_hwc_window = mirror_src_hwc->target_hwc_window; + EINA_SAFETY_ON_NULL_RETURN_VAL(src_target_hwc_window, EINA_FALSE); + + target_tsurface = target_hwc_window->hwc_window.buffer.tsurface; + src_target_tsurface = src_target_hwc_window->hwc_window.buffer.tsurface; + + if (hwc->mirror_src_tsurface == src_target_tsurface) return EINA_FALSE; + + if (hwc->pp_set) + { // TODO: mirror with pp + ; + } + else + { // mirror with sw copy fallback + queue = ((E_Hwc_Window *)target_hwc_window)->queue; + EINA_SAFETY_ON_NULL_RETURN_VAL(queue, EINA_FALSE); + + /* dequeue buffer */ + queue_buffer = e_hwc_window_queue_buffer_dequeue(queue); + EINA_SAFETY_ON_NULL_RETURN_VAL(queue_buffer, EINA_FALSE); + + /* copy */ + target_tsurface = queue_buffer->tsurface; + _e_hwc_windows_pixman_copy(hwc, src_target_tsurface, target_tsurface); + + /* enqueue buffer */ + e_hwc_window_queue_buffer_enqueue(queue, queue_buffer); + + /* fetch the buffer */ + _e_hwc_windows_target_buffer_fetch(hwc, EINA_TRUE); + } + + hwc->mirror_src_tsurface = src_target_tsurface; + + return EINA_TRUE; +} + +static Eina_Bool +_e_hwc_windows_presentation_changes_update(E_Hwc *hwc) +{ + /* set buffer */ + if (!e_hwc_window_buffer_fetch(hwc->presentation_hwc_window, EINA_TRUE)) + return EINA_FALSE; + + e_hwc_window_zpos_set(hwc->presentation_hwc_window, 0); + e_hwc_window_state_set(hwc->presentation_hwc_window, E_HWC_WINDOW_STATE_DEVICE, EINA_TRUE); + e_hwc_window_info_update(hwc->presentation_hwc_window); + + return EINA_TRUE; +} + +static Eina_Bool +_e_hwc_windows_presentation_evaluation_check(E_Hwc *hwc) +{ + E_Hwc_Window_State state; + E_Hwc_Window_Target *target_hwc_window; + tbm_surface_h target_tsurface, src_tsurface; + E_Hwc_Window_Queue *queue; + E_Hwc_Window_Queue_Buffer *queue_buffer = NULL; + + /* check if the window has the devcie type. */ + state = e_hwc_window_state_get(hwc->presentation_hwc_window); + if (state == E_HWC_WINDOW_STATE_DEVICE) return EINA_TRUE; + + /* copy the presentation_hwc_window to the target_window. */ + target_hwc_window = hwc->target_hwc_window; + EINA_SAFETY_ON_NULL_RETURN_VAL(target_hwc_window, EINA_FALSE); + + target_tsurface = target_hwc_window->hwc_window.buffer.tsurface; + + queue = ((E_Hwc_Window *)target_hwc_window)->queue; + EINA_SAFETY_ON_NULL_RETURN_VAL(queue, EINA_FALSE); + + /* dequeue buffer */ + queue_buffer = e_hwc_window_queue_buffer_dequeue(queue); + EINA_SAFETY_ON_NULL_RETURN_VAL(queue_buffer, EINA_FALSE); + + /* copy */ + src_tsurface = hwc->presentation_hwc_window->buffer.tsurface; + target_tsurface = queue_buffer->tsurface; + _e_hwc_windows_pixman_copy(hwc, src_tsurface, target_tsurface); + + /* enqueue buffer */ + e_hwc_window_queue_buffer_enqueue(queue, queue_buffer); + + /* fetch the buffer */ + _e_hwc_windows_target_buffer_fetch(hwc, EINA_TRUE); + + return EINA_TRUE; +} + +EINTERN Eina_Bool +e_hwc_windows_external_commit(E_Hwc *hwc, E_Output_Display_Mode display_mode) +{ + E_Output *output = NULL; + tdm_error error = TDM_ERROR_NONE; + + EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE); + + output = hwc->output; + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + + if (hwc->wait_commit) return EINA_TRUE; + + /* set the target_buffer if the output need to update */ +#if 1 + if (display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR) + { + if (!_e_hwc_windows_mirror_changes_update(hwc)) + return EINA_TRUE; + + if (!_e_hwc_windows_evaluate(hwc)) + return EINA_TRUE; + } + else if (display_mode == E_OUTPUT_DISPLAY_MODE_PRESENTATION) + { + if (!_e_hwc_windows_presentation_changes_update(hwc)) + return EINA_TRUE; + + if (!_e_hwc_windows_evaluate(hwc)) + return EINA_TRUE; + + /* if the presentation window is client type. copy it on the target window. */ + if (!_e_hwc_windows_presentation_evaluation_check(hwc)) + return EINA_TRUE; + } + else + { + EHWSERR("Unknown display_mode : %d", hwc, display_mode); + goto fail; + } +#else + if (!_e_hwc_windows_changes_update(hwc)) + return EINA_TRUE; + + if (!_e_hwc_windows_evaluate(hwc)) + return EINA_TRUE; +#endif + + if (e_hwc_norender_get(hwc) > 0) + { + EHWSTRACE(" Block Display... NoRender get.", NULL, hwc); + return EINA_TRUE; + } + + if (hwc->hwc_mode != E_HWC_MODE_FULL) { + if (!_e_hwc_windows_target_buffer_prepared(hwc)) + return EINA_TRUE; + } - EHWSTRACE("e_hwc_windows_mirror_unset", NULL, hwc); + if ((output->dpms == E_OUTPUT_DPMS_OFF) || (output->fake_config)) + { + _e_hwc_windows_offscreen_commit(hwc); + return EINA_TRUE; + } + + if (hwc->pp_set) + { + if (_e_hwc_windos_pp_pending_window_check(hwc)) + return EINA_TRUE; + } + + if (!_e_hwc_windows_commit_data_acquire(hwc)) + return EINA_TRUE; + + if (hwc->pp_unset) + hwc->pp_unset = EINA_FALSE; + + if (hwc->pp_set) + { + e_output_zoom_rotating_check(output); + _e_hwc_windows_update_fps(hwc); + if (!_e_hwc_windows_pp_commit(hwc)) + { + EHWSERR("_e_hwc_windows_pp_commit failed.", hwc); + goto fail; + } + } + else + { + EHWSTRACE("!!!!!!!! HWC Commit !!!!!!!!", NULL, hwc); + _e_hwc_windows_update_fps(hwc); + + hwc->wait_commit = EINA_TRUE; + + error = tdm_hwc_commit(hwc->thwc, 0, _e_hwc_windows_commit_handler, hwc); + if (error != TDM_ERROR_NONE) + { + EHWSERR("tdm_hwc_commit failed.", hwc); + _e_hwc_windows_commit_handler(hwc->thwc, 0, 0, 0, hwc); + goto fail; + } + } + + return EINA_TRUE; + +fail: + hwc->wait_commit = EINA_FALSE; + + return EINA_FALSE; } + diff --git a/src/bin/e_hwc_windows.h b/src/bin/e_hwc_windows.h index a913711..43050b9 100644 --- a/src/bin/e_hwc_windows.h +++ b/src/bin/e_hwc_windows.h @@ -38,6 +38,8 @@ EINTERN void e_hwc_windows_debug_info_get(Eldbus_Message_Iter *i EINTERN Eina_Bool e_hwc_windows_mirror_set(E_Hwc *hwc, E_Hwc *src_hwc, Eina_Rectangle *rect); EINTERN void e_hwc_windows_mirror_unset(E_Hwc *hwc); +EINTERN Eina_Bool e_hwc_windows_presentation_update(E_Hwc *hwc, E_Client *ec); +EINTERN Eina_Bool e_hwc_windows_external_commit(E_Hwc *hwc, E_Output_Display_Mode display_mode); #endif #endif diff --git a/src/bin/e_output.c b/src/bin/e_output.c index edff50d..eac47c7 100644 --- a/src/bin/e_output.c +++ b/src/bin/e_output.c @@ -25,6 +25,8 @@ while (0) #define DUMP_FPS 30 +#define OUTPUT_DELAY_CONNECT_CHECK_TIMEOUT 3.0 +#define OUTPUT_DELAY_CHECK_TIMEOUT 1.0 typedef struct _E_Output_Capture E_Output_Capture; typedef struct _E_Output_Layer E_Output_Layer; @@ -73,6 +75,68 @@ static Eina_Bool _e_output_capture(E_Output *output, tbm_surface_h tsurface, Ein static void _e_output_vblank_handler(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *data); +static unsigned int +_e_output_aligned_width_get(E_Output *output, tbm_surface_h tsurface) +{ + unsigned int aligned_width = 0; + tbm_surface_info_s surf_info; + + tbm_surface_get_info(tsurface, &surf_info); + + switch (surf_info.format) + { + case TBM_FORMAT_YUV420: + case TBM_FORMAT_YVU420: + case TBM_FORMAT_YUV422: + case TBM_FORMAT_YVU422: + case TBM_FORMAT_NV12: + case TBM_FORMAT_NV21: + aligned_width = surf_info.planes[0].stride; + break; + case TBM_FORMAT_YUYV: + case TBM_FORMAT_UYVY: + aligned_width = surf_info.planes[0].stride >> 1; + break; + case TBM_FORMAT_ARGB8888: + case TBM_FORMAT_XRGB8888: + aligned_width = surf_info.planes[0].stride >> 2; + break; + default: + EOERR("not supported format: %x", output, surf_info.format); + } + + return aligned_width; +} + +static Eina_Bool +_e_output_presentation_check(void *data) +{ + E_Output *output; + E_Output *primary_output; + + if (!data) return ECORE_CALLBACK_CANCEL; + + output = (E_Output *)data; + + if (e_output_display_mode_get(output) == E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION) + { + primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen); + e_output_mirror_set(output, primary_output); + } + + output->delay_timer = NULL; + + return ECORE_CALLBACK_CANCEL; +} + +static inline void +_e_output_display_mode_set(E_Output *output, E_Output_Display_Mode display_mode) +{ + if (output == NULL) return; + if (output->display_mode == display_mode) return; + + output->display_mode = display_mode; +} static void _e_output_hooks_clean(void) @@ -704,6 +768,71 @@ _e_output_client_resize(int w, int h) } } +static Eina_Bool +_e_output_external_connect_display_set(E_Output *output) +{ + E_Output *primary_output = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + + if (e_output_display_mode_get(output) == E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION) + { + EOINF("Start Wait Presentation", output); + + /* the fallback timer for not setting the presentation. */ + if (output->delay_timer) ecore_timer_del(output->delay_timer); + output->delay_timer = ecore_timer_add(OUTPUT_DELAY_CONNECT_CHECK_TIMEOUT, _e_output_presentation_check, output); + } + else + { + EOINF("Start Mirroring", output); + + primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen); + if (!e_output_mirror_set(output, primary_output)) + { + EOERR("e_output_mirror_set fails.", output); + return EINA_FALSE; + } + } + + EOINF("_e_output_external_connect_display_set done: display_mode:%d", output, e_output_display_mode_get(output)); + + return EINA_TRUE; +} + +static void +_e_output_external_disconnect_display_set(E_Output *output) +{ + EINA_SAFETY_ON_NULL_RETURN(output); + + switch (e_output_display_mode_get(output)) + { + case E_OUTPUT_DISPLAY_MODE_NONE: + break; + case E_OUTPUT_DISPLAY_MODE_MIRROR: + /* unset mirror */ + e_output_mirror_unset(output); + break; + case E_OUTPUT_DISPLAY_MODE_PRESENTATION: + /* only change the display_mode */ + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION); + break; + case E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION: + /* delete presentation_delay_timer */ + if (output->delay_timer) + { + ecore_timer_del(output->delay_timer); + output->delay_timer = NULL; + } + break; + default: + EOERR("unknown display_mode:%d", output, output->display_mode); + break; + } + + EOINF("_e_output_external_disconnect_display_set done.", output); +} + static void _e_output_primary_update(E_Output *output) { @@ -771,6 +900,101 @@ _e_output_primary_update(E_Output *output) } } +static Eina_Bool +_e_output_external_update(E_Output *output) +{ + E_Comp_Screen *e_comp_screen = NULL; + E_Output_Mode *mode = NULL; + E_Output *output_pri = NULL; + Eina_Bool ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + + e_comp_screen = e_comp->e_comp_screen; + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE); + + output_pri = e_comp_screen_primary_output_get(e_comp_screen); + if (!output_pri) + { + e_error_message_show(_("Fail to get the primary output!\n")); + return EINA_FALSE; + } + + if (output_pri == output) + return EINA_FALSE; + + + ret = e_output_update(output); + if (ret == EINA_FALSE) + { + EOERR("fail e_output_update.", output); + return EINA_FALSE; + } + + if (e_output_connected(output)) + { + mode = e_output_best_mode_find(output); + if (!mode) + { + EOERR("fail to get best mode.", output); + return EINA_FALSE; + } + + ret = e_output_mode_apply(output, mode); + if (ret == EINA_FALSE) + { + EOERR("fail to e_output_mode_apply.", output); + return EINA_FALSE; + } + ret = e_output_dpms_set(output, E_OUTPUT_DPMS_ON); + if (ret == EINA_FALSE) + { + EOERR("fail to e_output_dpms.", output); + return EINA_FALSE; + } + + ret = e_output_hwc_setup(output); + if (ret == EINA_FALSE) + { + EOERR("fail to e_output_hwc_setup.", output); + return EINA_FALSE; + } + + _e_output_hook_call(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, output); + + ret = _e_output_external_connect_display_set(output); + if (ret == EINA_FALSE) + { + EOERR("fail to _e_output_external_connect_display_set.", output); + return EINA_FALSE; + } + + EOINF("Connect the external output", output); + } + else + { + EOINF("Disconnect the external output", output); + + _e_output_hook_call(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, output); + + _e_output_external_disconnect_display_set(output); + + if (output->hwc) + { + e_hwc_del(output->hwc); + output->hwc = NULL; + } + + if (!e_output_dpms_set(output, E_OUTPUT_DPMS_OFF)) + { + EOERR("fail to e_output_dpms.", output); + return EINA_FALSE; + } + } + + return EINA_TRUE; +} + static void _e_output_cb_output_change(tdm_output *toutput, tdm_output_change_type type, @@ -802,7 +1026,7 @@ _e_output_cb_output_change(tdm_output *toutput, if (primary == output) _e_output_primary_update(output); else - e_output_external_update(output); + _e_output_external_update(output); } break; case TDM_OUTPUT_CHANGE_DPMS: @@ -1031,39 +1255,6 @@ _e_output_capture_position_get(E_Output *output, int dst_w, int dst_h, Eina_Rect return EINA_TRUE; } -static unsigned int -_e_output_aligned_width_get(E_Output *output, tbm_surface_h tsurface) -{ - unsigned int aligned_width = 0; - tbm_surface_info_s surf_info; - - tbm_surface_get_info(tsurface, &surf_info); - - switch (surf_info.format) - { - case TBM_FORMAT_YUV420: - case TBM_FORMAT_YVU420: - case TBM_FORMAT_YUV422: - case TBM_FORMAT_YVU422: - case TBM_FORMAT_NV12: - case TBM_FORMAT_NV21: - aligned_width = surf_info.planes[0].stride; - break; - case TBM_FORMAT_YUYV: - case TBM_FORMAT_UYVY: - aligned_width = surf_info.planes[0].stride >> 1; - break; - case TBM_FORMAT_ARGB8888: - case TBM_FORMAT_XRGB8888: - aligned_width = surf_info.planes[0].stride >> 2; - break; - default: - EOERR("not supported format: %x", output, surf_info.format); - } - - return aligned_width; -} - static E_Output_Capture * _e_output_tdm_stream_capture_find_data(E_Output *output, tbm_surface_h tsurface) { @@ -2100,42 +2291,6 @@ _e_output_external_rect_get(E_Output *output, int src_w, int src_h, int dst_w, i } static Eina_Bool -_e_output_external_commit(E_Output *output) -{ - E_Plane *plane = NULL; - - if (!output->external_set) return EINA_TRUE; - - if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) - { - /* external commit only primary */ - plane = e_output_fb_target_get(output); - - /* external commit */ - if (e_output_dpms_get(output)) - return EINA_TRUE; - - if (!e_plane_external_fetch(plane)) - return EINA_TRUE; - - if (!e_plane_external_commit(plane)) - { - EOERR("fail to e_plane_ex_commit", output); - return EINA_FALSE; - } - } - else - { - /* TODO: HWC Windows */; - /* external commit */ - if (e_output_dpms_get(output)) - return EINA_TRUE; - } - - return EINA_TRUE; -} - -static Eina_Bool _e_output_planes_commit(E_Output *output) { E_Plane *plane = NULL, *fb_target = NULL; @@ -2369,6 +2524,9 @@ e_output_new(E_Comp_Screen *e_comp_screen, int index) if (output_caps & TDM_OUTPUT_CAPABILITY_ASYNC_DPMS) output->dpms_async = EINA_TRUE; + if (output_caps & TDM_OUTPUT_CAPABILITY_MIRROR) + output->tdm_mirror = EINA_TRUE; + /* call output add hook */ _e_output_hook_call(E_OUTPUT_HOOK_ADD, output); @@ -3056,10 +3214,13 @@ e_output_render(E_Output *output) return EINA_TRUE; } +static int boot_launch = 0; + EINTERN Eina_Bool e_output_commit(E_Output *output) { E_Output *output_primary = NULL; + E_Output_Display_Mode display_mode; EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); @@ -3086,21 +3247,53 @@ e_output_commit(E_Output *output) } else { - if (!_e_output_external_commit(output)) + display_mode = e_output_display_mode_get(output); + + /* output donot care about the external_commit + when tdm has the mirror capability */ + if (display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR && + output->tdm_mirror) + return EINA_TRUE; + + if (!e_hwc_planes_external_commit(output->hwc)) { - EOERR("fail _e_output_external_commit", output); + EOERR("fail e_hwc_planes_external_commit", output); return EINA_FALSE; } } } else { - /* commit the only primary output */ - if (output != output_primary) return EINA_TRUE; - - if (!e_hwc_windows_commit(output->hwc)) + if (output == output_primary) { - return EINA_FALSE; + if (!e_hwc_windows_commit(output->hwc)) + { + EOERR("fail e_hwc_windows_commit", output); + return EINA_FALSE; + } + } + else + { + /* trigger the output_external_update at the launching time */ + if (!boot_launch) + { + boot_launch = 1; + _e_output_external_update(output); + } + + display_mode = e_output_display_mode_get(output); + + /* output donot care about the external_commit + when tdm has the mirror capability */ + if (display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR && + output->tdm_mirror) + return EINA_TRUE; + + if (!e_hwc_windows_external_commit(output->hwc, display_mode)) + { + EOERR("fail e_hwc_windows_external_commit", output); + return EINA_FALSE; + } } } @@ -3798,256 +3991,286 @@ e_output_stream_capture_stop(E_Output *output) } EINTERN Eina_Bool -e_output_external_set(E_Output *output, E_Output_Display_Mode display_mode) +e_output_external_mode_change(E_Output *output, E_Output_Mode *mode) { + E_Output_Mode *emode = NULL, *current_emode = NULL; + Eina_List *l; + Eina_Bool found = EINA_FALSE; E_Output *output_primary = NULL; E_Plane *ep = NULL; int w, h, p_w, p_h; EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(mode, EINA_FALSE); - output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen); - EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL(output_primary == output, EINA_FALSE); + if (e_output_connected(output) != EINA_TRUE) + return EINA_FALSE; - if (output->display_mode == display_mode) - return EINA_TRUE; - output->display_mode = display_mode; + current_emode = e_output_current_mode_get( output); + EINA_SAFETY_ON_NULL_RETURN_VAL(current_emode, EINA_FALSE); - e_output_size_get(output, &w, &h); - e_output_size_get(output_primary, &p_w, &p_h); + if (current_emode == mode) + return EINA_TRUE; - if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) + EINA_LIST_FOREACH(output->info.modes, l, emode) { - ep = e_output_fb_target_get(output); - EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE); - - _e_output_external_rect_get(output_primary, p_w, p_h, w, h, &output->zoom_conf.rect); - - e_hwc_planes_multi_plane_set(output_primary->hwc, EINA_FALSE); - - ep->output_primary = output_primary; - if (!e_plane_external_set(ep, &output->zoom_conf.rect, display_mode)) + if (mode == emode) { - EOERR("e_plane_mirror_set failed.", output); - e_hwc_planes_multi_plane_set(output_primary->hwc, EINA_TRUE); - - return EINA_FALSE; + found = EINA_TRUE; + break; } } - else - { - /* TODO: HWC Windows */; - return EINA_FALSE; - } - - output->display_mode = display_mode; - output->external_set = EINA_TRUE; - - EOINF("e_output_external_set done: display_mode:%d", output, display_mode); + EINA_SAFETY_ON_FALSE_RETURN_VAL(found == EINA_TRUE, EINA_FALSE); - /* update the ecore_evas */ - _e_output_force_render_set(output_primary); + output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen); + EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(output_primary == output, EINA_FALSE); - return EINA_TRUE; -} + e_output_size_get(output, &w, &h); + e_output_size_get(output_primary, &p_w, &p_h); -EINTERN void -e_output_external_unset(E_Output *output) -{ - E_Output *output_primary = NULL; - E_Plane *ep = NULL; + e_comp_canvas_norender_push(); - EINA_SAFETY_ON_NULL_RETURN(output); + if (e_output_mode_apply(output, mode) == EINA_FALSE) + { + EOERR("fail to e_output_mode_apply.", output); + e_comp_canvas_norender_pop(); + return EINA_FALSE; + } - output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen); - EINA_SAFETY_ON_NULL_RETURN(output_primary); - EINA_SAFETY_ON_TRUE_RETURN(output_primary == output); + _e_output_external_rect_get(output_primary, p_w, p_h, w, h, &output->zoom_conf.rect); - if (output->display_mode == E_OUTPUT_DISPLAY_MODE_NONE) - return; + /* call mode change hook */ + _e_output_hook_call(E_OUTPUT_HOOK_MODE_CHANGE, output); - output->external_set = EINA_FALSE; - output->display_mode = E_OUTPUT_DISPLAY_MODE_NONE; + EOINF("mode change output: (%dx%d)", output, w, h); + if (e_output_display_mode_get(output) == E_OUTPUT_DISPLAY_MODE_PRESENTATION) + { + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION); + if (output->delay_timer) ecore_timer_del(output->delay_timer); + output->delay_timer = ecore_timer_add(OUTPUT_DELAY_CONNECT_CHECK_TIMEOUT, _e_output_presentation_check, output); + } if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) { ep = e_output_fb_target_get(output); - EINA_SAFETY_ON_NULL_RETURN(ep); - - e_plane_external_unset(ep); + EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE); - e_hwc_planes_multi_plane_set(output_primary->hwc, EINA_TRUE); + e_plane_external_reset(ep, &output->zoom_conf.rect); } else { /* TODO: HWC Windows */; } - output->zoom_conf.rect.x = 0; - output->zoom_conf.rect.y = 0; - output->zoom_conf.rect.w = 0; - output->zoom_conf.rect.h = 0; + _e_output_render_update(output_primary); + e_comp_canvas_norender_pop(); - /* update the ecore_evas */ - _e_output_force_render_set(output_primary); + EOINF("e_output_external_reset done.(%dx%d)", output, mode->w, mode->h); - EOINF("e_output_external_unset done.", output); + return EINA_TRUE; } EINTERN Eina_Bool -e_output_external_update(E_Output *output) +e_output_mirror_set(E_Output *output, E_Output *src_output) { - E_Comp_Screen *e_comp_screen = NULL; - E_Output_Mode *mode = NULL; - E_Output *output_pri = NULL; - Eina_Bool ret; + tdm_error ret; + int w, h, p_w, p_h; EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(src_output, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(output->hwc, EINA_FALSE); - e_comp_screen = e_comp->e_comp_screen; - EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE); - - output_pri = e_comp_screen_primary_output_get(e_comp_screen); - if (!output_pri) + if (output->display_mode == E_OUTPUT_DISPLAY_MODE_MIRROR) { - e_error_message_show(_("Fail to get the primary output!\n")); - return EINA_FALSE; + EOINF("Already Set MIRROR_MODE", output); + return EINA_TRUE; } - if (output_pri == output) - return EINA_FALSE; - - - ret = e_output_update(output); - if (ret == EINA_FALSE) + if (output->tdm_mirror) { - EOERR("fail e_output_update.", output); - return EINA_FALSE; - } + EOINF("TDM supports the output mirroring.", output); - if (e_output_connected(output)) - { - mode = e_output_best_mode_find(output); - if (!mode) + ret = tdm_output_set_mirror(output->toutput, src_output->toutput, TDM_TRANSFORM_NORMAL); + if (ret != TDM_ERROR_NONE) { - EOERR("fail to get best mode.", output); + EOINF("tdm_output_set_mirror fails.", output); return EINA_FALSE; } + } + else + { + e_output_size_get(output, &w, &h); + e_output_size_get(src_output, &p_w, &p_h); - ret = e_output_mode_apply(output, mode); - if (ret == EINA_FALSE) + _e_output_external_rect_get(src_output, p_w, p_h, w, h, &output->zoom_conf.rect); + + if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) { - EOERR("fail to e_output_mode_apply.", output); - return EINA_FALSE; + if (!e_hwc_planes_mirror_set(output->hwc, src_output->hwc, &output->zoom_conf.rect)) + { + EOERR("e_hwc_planes_mirror_set failed.", output); + return EINA_FALSE; + } } - ret = e_output_dpms_set(output, E_OUTPUT_DPMS_ON); - if (ret == EINA_FALSE) + else { - EOERR("fail to e_output_dpms.", output); - return EINA_FALSE; + /* set the target_buffer of the src_hwc to the target_buffer of the dst_hwc with zoom rect */ + if (!e_hwc_windows_mirror_set(output->hwc, src_output->hwc, &output->zoom_conf.rect)) + { + EOERR("e_hwc_windows_mirror_set failed.", output); + return EINA_FALSE; + } } + } - ret = e_output_hwc_setup(output); - if (ret == EINA_FALSE) - { - EOERR("fail to e_output_hwc_setup.", output); - return EINA_FALSE; - } + output->mirror_src_output = src_output; - _e_output_hook_call(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, output); + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_MIRROR); + output->external_set = EINA_TRUE; + + /* update the ecore_evas of the src_output */ + _e_output_force_render_set(src_output); + + EOINF("e_output_mirror_set done: E_OUTPUT_DISPLAY_MODE_MIRROR", output); + + return EINA_TRUE; +} + +EINTERN void +e_output_mirror_unset(E_Output *output) +{ + E_Output *src_output; + tdm_error ret; + + EINA_SAFETY_ON_NULL_RETURN(output); + + EOINF("e_output_mirror_unset: E_OUTPUT_DISPLAY_MODE_NONE", output); + + src_output = output->mirror_src_output; + + /* update the ecore_evas of the src_output */ + _e_output_render_update(src_output); + + output->external_set = EINA_FALSE; + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_NONE); + + output->mirror_src_output = NULL; + + if (output->tdm_mirror) + { + ret = tdm_output_unset_mirror(output->toutput); + if (ret != TDM_ERROR_NONE) + EOERR("tdm_output_unset_mirror fails.", output); } else { - _e_output_hook_call(E_OUTPUT_HOOK_CONNECT_STATUS_CHANGE, output); + if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) + e_hwc_planes_mirror_unset(output->hwc); + else + e_hwc_windows_mirror_unset(output->hwc); + } +} - if (output->hwc) - { - e_hwc_del(output->hwc); - output->hwc = NULL; - } +EINTERN Eina_Bool +e_output_presentation_wait_set(E_Output *output, E_Client *ec) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ec, EINA_FALSE); - if (!e_output_dpms_set(output, E_OUTPUT_DPMS_OFF)) - { - EOERR("fail to e_output_dpms.", output); - return EINA_FALSE; - } + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION); + + /* the ec does not commit the buffer to the exernal output + * Therefore, it needs the timer to prevent the eternal waiting. + */ + if (output->delay_timer) + { + ecore_timer_del(output->delay_timer); + output->delay_timer = ecore_timer_add(OUTPUT_DELAY_CHECK_TIMEOUT, _e_output_presentation_check, output); } + EOINF("e_output_presentation_wait_set done: E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION", output); + return EINA_TRUE; } EINTERN Eina_Bool -e_output_external_mode_change(E_Output *output, E_Output_Mode *mode) +e_output_presentation_update(E_Output *output, E_Client *ec) { - E_Output_Mode *emode = NULL, *current_emode = NULL; - Eina_List *l; - Eina_Bool found = EINA_FALSE; - E_Output *output_primary = NULL; - E_Plane *ep = NULL; - int w, h, p_w, p_h; + E_Hwc *hwc; + E_Output_Display_Mode display_mode; - EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(mode, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ec, EINA_FALSE); - if (e_output_connected(output) != EINA_TRUE) - return EINA_FALSE; + hwc = output->hwc; + EINA_SAFETY_ON_FALSE_RETURN_VAL(hwc, EINA_FALSE); - current_emode = e_output_current_mode_get( output); - EINA_SAFETY_ON_NULL_RETURN_VAL(current_emode, EINA_FALSE); + display_mode = e_output_display_mode_get(output); + EINA_SAFETY_ON_FALSE_RETURN_VAL(display_mode == E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION, EINA_FALSE); - if (current_emode == mode) - return EINA_TRUE; + /* delete the delay timer on E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION */ + if (output->delay_timer) ecore_timer_del(output->delay_timer); + output->delay_timer = NULL; - EINA_LIST_FOREACH(output->info.modes, l, emode) + if (e_hwc_policy_get(hwc) == E_HWC_POLICY_PLANES) { - if (mode == emode) + if (!e_hwc_planes_presentation_update(hwc, ec)) { - found = EINA_TRUE; - break; + EOERR("e_hwc_planes_presentation_update fails.", output); + return EINA_FALSE; + } + } + else + { + if (!e_hwc_windows_presentation_update(hwc, ec)) + { + EOERR("e_hwc_windows_presentation_update fails.", output); + return EINA_FALSE; } } - EINA_SAFETY_ON_FALSE_RETURN_VAL(found == EINA_TRUE, EINA_FALSE); - output_primary = e_comp_screen_primary_output_get(e_comp->e_comp_screen); - EINA_SAFETY_ON_NULL_RETURN_VAL(output_primary, EINA_FALSE); - EINA_SAFETY_ON_TRUE_RETURN_VAL(output_primary == output, EINA_FALSE); + output->presentation_ec = ec; + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_PRESENTATION); - e_output_size_get(output, &w, &h); - e_output_size_get(output_primary, &p_w, &p_h); + output->external_set = EINA_TRUE; - ep = e_output_fb_target_get(output); - EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE); + EOINF("e_output_presentation_update done: E_OUTPUT_DISPLAY_MODE_PRESENTATION", output); - e_comp_canvas_norender_push(); + return EINA_TRUE; +} - if (e_output_mode_apply(output, mode) == EINA_FALSE) - { - EOERR("fail to e_output_mode_apply.", output); - e_comp_canvas_norender_pop(); - return EINA_FALSE; - } +EINTERN void +e_output_presentation_unset(E_Output *output) +{ + E_Hwc *hwc; - _e_output_external_rect_get(output_primary, p_w, p_h, w, h, &output->zoom_conf.rect); + EINA_SAFETY_ON_FALSE_RETURN(output); - /* call mode change hook */ - _e_output_hook_call(E_OUTPUT_HOOK_MODE_CHANGE, output); + hwc = output->hwc; + EINA_SAFETY_ON_FALSE_RETURN(hwc); - if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES) - { - e_plane_external_reset(ep, &output->zoom_conf.rect); - } - else - { - /* TODO: HWC Windows */; - } + /* delete the delay timer on E_OUTPUT_DISPLAY_MODE_WAIT_PRESENTATION */ + if (output->delay_timer) ecore_timer_del(output->delay_timer); + output->delay_timer = NULL; - _e_output_render_update(output_primary); - e_comp_canvas_norender_pop(); + output->external_set = EINA_FALSE; - EOINF("e_output_external_reset done.(%dx%d)", output, mode->w, mode->h); + _e_output_display_mode_set(output, E_OUTPUT_DISPLAY_MODE_NONE); + output->presentation_ec = NULL; - return EINA_TRUE; + if (e_hwc_policy_get(hwc) == E_HWC_POLICY_PLANES) + e_hwc_planes_presentation_update(hwc, NULL); + else + e_hwc_windows_presentation_update(hwc, NULL); +} + +EINTERN E_Client * +e_output_presentation_ec_get(E_Output *output) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(output, NULL); + + return output->presentation_ec; } EINTERN E_Output_Display_Mode diff --git a/src/bin/e_output.h b/src/bin/e_output.h index a999e84..9ec81ae 100644 --- a/src/bin/e_output.h +++ b/src/bin/e_output.h @@ -128,7 +128,17 @@ struct _E_Output /* external */ Eina_Bool external_set; + Eina_Bool tdm_mirror; + E_Output *mirror_src_output; E_Output_Display_Mode display_mode; + tdm_layer *overlay_layer; + Eina_Bool need_overlay_pp; + E_Client *presentation_ec; + /* If attribute has been set while external output is disconnected + * then show black screen and wait until EOM client start sending + * buffers. After expiring of the delay start mirroring */ + Ecore_Timer *delay_timer; + Eina_Bool force_render; Eina_Bool fake_config; @@ -228,10 +238,14 @@ EINTERN Eina_Bool e_output_stream_capture_dequeue(E_Output *output, tbm_ EINTERN Eina_Bool e_output_stream_capture_start(E_Output *output); EINTERN void e_output_stream_capture_stop(E_Output *output); EINTERN const char * e_output_output_id_get(E_Output *output); -EINTERN Eina_Bool e_output_external_set(E_Output *output, E_Output_Display_Mode display_mode); -EINTERN void e_output_external_unset(E_Output *output); -EINTERN Eina_Bool e_output_external_update(E_Output *output); + EINTERN Eina_Bool e_output_external_mode_change(E_Output *output, E_Output_Mode *mode); +EINTERN Eina_Bool e_output_mirror_set(E_Output *output, E_Output *src_output); +EINTERN void e_output_mirror_unset(E_Output *output); +EINTERN Eina_Bool e_output_presentation_wait_set(E_Output *output, E_Client *ec); +EINTERN Eina_Bool e_output_presentation_update(E_Output *output, E_Client *ec); +EINTERN void e_output_presentation_unset(E_Output *output); +EINTERN E_Client * e_output_presentation_ec_get(E_Output *output); EINTERN E_Output_Display_Mode e_output_display_mode_get(E_Output *output); -- 2.7.4