implement new mechanism for smooth transition from DEVICE to CLIENT 56/163356/5
authorSergey Sizonov <s.sizonov@samsung.com>
Mon, 11 Dec 2017 11:11:19 +0000 (14:11 +0300)
committerSergey Sizonov <s.sizonov@samsung.com>
Wed, 13 Dec 2017 15:29:39 +0000 (18:29 +0300)
This implementation is based on the list of composited
hwc_wnds passed along with target_surface these hwc_wnds
are composited at.

Change-Id: I8f2b1c5b8bc1d6df4f271707dedefa0c5e826362
Signed-off-by: Sergey Sizonov <s.sizonov@samsung.com>
src/tdm_exynos.h
src/tdm_exynos_output.c
src/tdm_exynos_types.h
src/tdm_exynos_window.c

index 76f5bf54e0c7be873feac30146af5bf79b8ed956..9d9514d233cff6e245907592eed555f7e0f16ef0 100644 (file)
@@ -66,7 +66,8 @@ tdm_error    exynos_output_hwc_get_changed_composition_types(tdm_output *output,
 tdm_error    exynos_output_hwc_accept_changes(tdm_output *output);
 tbm_surface_queue_h exynos_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error);
 tdm_error    exynos_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
-                                                                       tdm_hwc_region damage);
+                                                                       tdm_hwc_region damage, tdm_hwc_window **composited_wnds,
+                                                                       uint32_t num_wnds);
 tdm_error    exynos_output_hwc_get_video_supported_formats(tdm_output *output, const tbm_format **formats, int *count);
 tdm_hwc_window *exynos_output_hwc_create_video_window(tdm_output *output, tdm_error *error);
 tdm_error    exynos_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
index 39b2a7b04af250e47697db1682405264bcb257c2..99b8618f08f2d0cc35b62faf3cd383144a5061aa 100644 (file)
@@ -882,19 +882,74 @@ _find_maped_hwc_window_to_layer(struct list_head *hwc_wnds, int layer_zpos)
                        continue;
 
                if (hw->assigned_layer_zpos == layer_zpos &&
-                       hw->validated_type == TDM_COMPOSITION_DEVICE)
+                       (hw->validated_type == TDM_COMPOSITION_DEVICE || hw->is_device_to_client_transition))
                        return hw;
        }
 
        return NULL;
 }
 
+static void
+_update_layers_info(tdm_exynos_output_data *output_data)
+{
+       tdm_exynos_layer_data *layer = NULL;
+       tdm_exynos_hwc_window_data *hw;
+       int primary_layer_zpos = _get_primary_layer_zpos(output_data);
+       tdm_error ret;
+
+       LIST_FOR_EACH_ENTRY(layer, &output_data->layer_list, link) {
+               if (output_data->need_target_window && layer->zpos == primary_layer_zpos)
+                       hw = output_data->target_hwc_window;
+               else
+                       hw = _find_maped_hwc_window_to_layer(&output_data->hwc_window_list, layer->zpos);
+
+               if (hw) {
+                       ret = exynos_layer_set_info((tdm_layer *)layer,
+                                                                               (tdm_info_layer *)&(hw->info));
+                       if (ret != TDM_ERROR_NONE)
+                               TDM_ERR("cannot set info to layer with %d zpos", layer->zpos);
+               }
+       }
+}
+
+static int
+_is_device_to_client_transition_finished(struct list_head *hwc_wnds)
+{
+       tdm_exynos_hwc_window_data *hw = NULL;
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+               if (hw->client_type == TDM_COMPOSITION_NONE)
+                       continue;
+
+               if (hw->is_device_to_client_transition)
+                       goto work;
+       }
+
+       TDM_INFO("no device to client transition.");
+
+       /* if there wasn't the device to client transition there's no
+        * the device to client transition end :) */
+       return 0;
+
+work:
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+               if (hw->client_type == TDM_COMPOSITION_NONE)
+                       continue;
+
+               if (hw->is_device_to_client_transition && !hw->present_on_target_wnd)
+                       return 0;
+       }
+
+       return 1;
+}
+
 static tdm_error
 _tdm_exynos_display_prepare_commit(tdm_exynos_output_data *output_data) {
 
        tdm_exynos_layer_data *layer = NULL;
-       tdm_exynos_hwc_window_data *hw;
+       tdm_exynos_hwc_window_data *hw = NULL;
        int primary_layer_zpos = _get_primary_layer_zpos(output_data);
+       int device_to_client_transition_finished;
 
        RETURN_VAL_IF_FAIL(output_data->need_validate == 0, TDM_ERROR_OPERATION_FAILED);
 
@@ -909,6 +964,44 @@ _tdm_exynos_display_prepare_commit(tdm_exynos_output_data *output_data) {
                _set_hwc_window_buffer_to_layer(layer, output_data->video_hwc_window);
        }
 
+       device_to_client_transition_finished =
+                       _is_device_to_client_transition_finished(&output_data->hwc_window_list);
+
+       if (device_to_client_transition_finished) {
+               LIST_FOR_EACH_ENTRY(hw, &output_data->hwc_window_list, link) {
+                       if (hw->client_type == TDM_COMPOSITION_NONE)
+                               continue;
+
+                       if (hw->is_device_to_client_transition)
+                               hw->surface = NULL; /* to unset layers */
+               }
+
+               TDM_INFO("the device to client transition has finished, need_target_wnd:%d",
+                               output_data->need_target_window);
+
+               /* if at the moment tdm-backend found a device to client transition
+                * the target_wnd was turned off, we'll skip one frame for target_buffer
+                * without the next lines */
+               if (!output_data->need_target_window) {
+                       output_data->need_target_window = 1;
+
+                       layer = _exynos_output_get_layer(output_data, primary_layer_zpos);
+                       _set_hwc_window_buffer_to_layer(layer, output_data->target_hwc_window);
+
+                       /* preempt the hwc_wnd which was mapped to the primary layer */
+                       hw = _find_maped_hwc_window_to_layer(&output_data->hwc_window_list, primary_layer_zpos);
+                       hw->assigned_layer_zpos = -1;
+                       hw->prev_assigned_layer_zpos = -1;
+
+                       _update_layers_info(output_data);
+               }
+
+               /* tdm-backend resets all hwc_wnds to CLIENTs while there's any hwc_wnd
+                * within 'device to client transition' state, so after such transition
+                * has finished, we trigger a revalidate event to reevaluate the overlay policy */
+               tdm_backend_trigger_need_validate_event(output_data);
+       }
+
        LIST_FOR_EACH_ENTRY(layer, &output_data->layer_list, link) {
                if (output_data->need_target_window && layer->zpos == primary_layer_zpos)
                        continue;
@@ -919,6 +1012,17 @@ _tdm_exynos_display_prepare_commit(tdm_exynos_output_data *output_data) {
                _set_hwc_window_buffer_to_layer(layer, hw);
        }
 
+       if (device_to_client_transition_finished) {
+               hw = NULL;
+
+               LIST_FOR_EACH_ENTRY(hw, &output_data->hwc_window_list, link) {
+                       if (hw->client_type == TDM_COMPOSITION_NONE)
+                               continue;
+
+                       hw->is_device_to_client_transition = 0;
+               }
+       }
+
        return TDM_ERROR_NONE;
 }
 
@@ -1554,39 +1658,84 @@ _print_validate_result(tdm_exynos_output_data *exynos_output)
 }
 
 static void
-_update_layers_info(tdm_exynos_output_data *output_data)
+_reset_buffers_for_unvis_hwc_windows(tdm_exynos_output_data *output_data)
 {
-       tdm_exynos_layer_data *layer = NULL;
-       tdm_exynos_hwc_window_data *hw;
-       int primary_layer_zpos = _get_primary_layer_zpos(output_data);
-       tdm_error ret;
+       tdm_exynos_hwc_window_data *hw = NULL;
 
-       LIST_FOR_EACH_ENTRY(layer, &output_data->layer_list, link) {
-               if (output_data->need_target_window && layer->zpos == primary_layer_zpos)
-                       hw = output_data->target_hwc_window;
-               else
-                       hw = _find_maped_hwc_window_to_layer(&output_data->hwc_window_list, layer->zpos);
+       if (!output_data->need_target_window)
+               output_data->target_hwc_window->surface = NULL;
 
-               if (hw) {
-                       ret = exynos_layer_set_info((tdm_layer *)layer,
-                                                                               (tdm_info_layer *)&(hw->info));
-                       if (ret != TDM_ERROR_NONE)
-                               TDM_ERR("cannot set info to layer with %d zpos", layer->zpos);
+       LIST_FOR_EACH_ENTRY(hw, &output_data->hwc_window_list, link)
+               if (hw->client_type == TDM_COMPOSITION_NONE)
+                       hw->surface = NULL;
+}
+
+static void
+_restore_windows_assigned_layer_zpos(struct list_head *hwc_wnds)
+{
+       tdm_exynos_hwc_window_data *hw = NULL;
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+               if (hw->client_type == TDM_COMPOSITION_NONE) {
+                       hw->assigned_layer_zpos = -1;
+                       continue;
                }
+
+               hw->assigned_layer_zpos = hw->prev_assigned_layer_zpos;
        }
 }
 
 static void
-_reset_buffers_for_unvis_hwc_windows(tdm_exynos_output_data *output_data)
+_reset_windows_to_client(struct list_head *hwc_wnds)
 {
        tdm_exynos_hwc_window_data *hw = NULL;
 
-       if (!output_data->need_target_window)
-               output_data->target_hwc_window->surface = NULL;
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+               if (hw->client_type == TDM_COMPOSITION_NONE)
+                       continue;
 
-       LIST_FOR_EACH_ENTRY(hw, &output_data->hwc_window_list, link)
+               if (hw->prev_validated_type == TDM_COMPOSITION_DEVICE &&
+                               hw->validated_type == TDM_COMPOSITION_CLIENT)
+                       hw->is_device_to_client_transition = 1;
+
+               hw->validated_type = TDM_COMPOSITION_CLIENT;
+       }
+
+       /* move to 'device to client transition' state hwc_wnds
+        * which were mapped to overlays, but which weren't reset to
+        * CLIENT by e20 or _map_hwc_windows_to_layers() func */
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
                if (hw->client_type == TDM_COMPOSITION_NONE)
-                       hw->surface = NULL;
+                       continue;
+
+               if (hw->prev_validated_type == TDM_COMPOSITION_DEVICE &&
+                               hw->validated_type == TDM_COMPOSITION_CLIENT)
+                       hw->is_device_to_client_transition = 1;
+       }
+}
+
+/* if we got at least one device -> client transition or we have
+ * at least one window in 'device to client transitional state' we
+ * reset all windows to the client state, as it's a reference
+ * implementation of the driver */
+static int
+_is_reset_to_client_needed(struct list_head *hwc_wnds)
+{
+       tdm_exynos_hwc_window_data *hw = NULL;
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+               if (hw->client_type == TDM_COMPOSITION_NONE)
+                       continue;
+
+               if (hw->prev_validated_type == TDM_COMPOSITION_DEVICE &&
+                               hw->validated_type == TDM_COMPOSITION_CLIENT)
+                       return 1;
+
+               if (hw->is_device_to_client_transition)
+                       return 1;
+       }
+
+       return 0;
 }
 
 tdm_error
@@ -1597,6 +1746,8 @@ exynos_output_hwc_validate(tdm_output *output, uint32_t *num_types)
        RETURN_VAL_IF_FAIL(exynos_output != NULL, TDM_ERROR_INVALID_PARAMETER);
        RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
        int need_map_hwc_windows_to_layers;
+       int need_reset_to_client;
+       int prev_need_target_window;
 
        exynos_data = exynos_output->exynos_data;
        RETURN_VAL_IF_FAIL(exynos_data != NULL, TDM_ERROR_INVALID_PARAMETER);
@@ -1606,6 +1757,9 @@ exynos_output_hwc_validate(tdm_output *output, uint32_t *num_types)
 
                _reset_composition_types(&exynos_output->hwc_window_list);
        } else {
+       
+               prev_need_target_window = exynos_output->need_target_window;
+
                /* if previous mapping can be used it is not needed to remap hwc_windows
                 * to layers */
                need_map_hwc_windows_to_layers = _need_map_hwc_windows_to_layers(exynos_output);
@@ -1613,6 +1767,16 @@ exynos_output_hwc_validate(tdm_output *output, uint32_t *num_types)
                if (need_map_hwc_windows_to_layers)
                        _map_hwc_windows_to_layers(exynos_output);
 
+               need_reset_to_client = _is_reset_to_client_needed(&exynos_output->hwc_window_list);
+               if (need_reset_to_client) {
+                       TDM_INFO("reset all hwc_wnds to CLIENT.");
+
+                       _reset_windows_to_client(&exynos_output->hwc_window_list);
+                       _restore_windows_assigned_layer_zpos(&exynos_output->hwc_window_list);
+
+                       exynos_output->need_target_window = prev_need_target_window;
+               }
+
                _update_windows_previous_type(&exynos_output->hwc_window_list);
                _update_windows_previous_assigned_layer_zpos(&exynos_output->hwc_window_list);
        }
@@ -1716,9 +1880,12 @@ exynos_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error)
 
 tdm_error
 exynos_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
-                                                                       tdm_hwc_region damage)
+                                                                       tdm_hwc_region damage, tdm_hwc_window **composited_wnds,
+                                                                       uint32_t num_wnds)
 {
        tdm_exynos_output_data *exynos_output = output;
+       tdm_exynos_hwc_window_data **exynos_hwc_window = NULL;
+       tdm_exynos_hwc_window_data *hw = NULL;
        tdm_error err;
 
        RETURN_VAL_IF_FAIL(exynos_output != NULL, TDM_ERROR_INVALID_PARAMETER);
@@ -1730,6 +1897,24 @@ exynos_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buf
        err = exynos_hwc_window_set_buffer_damage(exynos_output->target_hwc_window, damage);
        RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
 
+       /* TODO: sergs: think about it
+        * a hack to allow the e-boot-animation to be shown */
+       if (!composited_wnds || !num_wnds)
+               return TDM_ERROR_NONE;
+
+       /* to keep a list up to date with one provided by e20 */
+       LIST_FOR_EACH_ENTRY(hw, &exynos_output->hwc_window_list, link)
+               hw->present_on_target_wnd = 0;
+
+       exynos_hwc_window = (tdm_exynos_hwc_window_data**)composited_wnds;
+
+       for (uint32_t i = 0; i < num_wnds; i++)
+               exynos_hwc_window[i]->present_on_target_wnd = 1;
+
+       LIST_FOR_EACH_ENTRY(hw, &exynos_output->hwc_window_list, link)
+               if (hw->present_on_target_wnd)
+                       TDM_INFO("hwc_wnd:%p presents on the target window.", hw);
+
        return TDM_ERROR_NONE;
 }
 
index ac3c6c765b55df0e4f355afd8351ab4ca26c7728..566ff93328c34cb819e42aa426d6327435e47e0e 100644 (file)
@@ -205,6 +205,9 @@ struct _tdm_exynos_hwc_window_data {
        int prev_assigned_layer_zpos;
 
        tdm_hwc_window_flag flags;
+
+       int present_on_target_wnd;
+       int is_device_to_client_transition;
 };
 
 struct _tdm_exynos_display_buffer {
index 7b30eb2353bb8fbcc9ed4c2e41d3719479a40fb4..6d8a3b53eca57b9368c9f2e434960cbab2172033 100644 (file)
@@ -145,6 +145,11 @@ exynos_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface)
        RETURN_VAL_IF_FAIL(exynos_output != NULL, err);
        RETURN_VAL_IF_FAIL(exynos_data != NULL, err);
 
+       /* we can't allow a hwc_wnd within 'device to client transition' state
+        * to be updated, 'cause it may lead to incorrect order of shown buffers */
+       if (exynos_hwc_window->is_device_to_client_transition)
+               return TDM_ERROR_BUSY;
+
        if (exynos_hwc_window->surface == surface)
                return TDM_ERROR_NONE;