hwc: implement smooth transition from device to client 57/158857/1
authorKonstantin Drabeniuk <k.drabeniuk@samsung.com>
Tue, 24 Oct 2017 08:29:41 +0000 (11:29 +0300)
committerRoman Marchenko <r.marchenko@samsung.com>
Fri, 3 Nov 2017 10:19:35 +0000 (12:19 +0200)
This implementation is based on the exynos implementation

If a window with the device composition type changes a type to the client
composition type (by the e20 demands or by the driver demands) we got the
flickering as a buffer owned by this window can't be composited to the
fb_target immediately.

So we delay the unset of a hw overlay owned by this window till
the buffer get composited to the fb_target.

Change-Id: I349f752dfa71c87545f785c4eb22ce073f7cb183
Signed-off-by: Konstantin Drabeniuk <k.drabeniuk@samsung.com>
src/tdm_sprd_display.c

index 74d6027..c36ae28 100644 (file)
@@ -146,6 +146,8 @@ struct _tdm_sprd_hwc_window_data {
        tdm_hwc_window_composition client_type;
        /* validated_type stores the type after running Validate */
        tdm_hwc_window_composition validated_type;
+       /* prev_validated_type is used to achieve requirements tied with the client_candidate type */
+       tdm_hwc_window_composition prev_validated_type;
 
        tdm_hwc_window_flag flags;
 };
@@ -1186,6 +1188,25 @@ sprd_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler fun
        return TDM_ERROR_NONE;
 }
 
+static int
+_are_windows_with_client_candidate_type(struct list_head *hwc_wnds)
+{
+       tdm_sprd_hwc_window_data *hw = NULL;
+
+       RETURN_VAL_IF_FAIL(hwc_wnds, 0);
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               if (hw->validated_type == TDM_COMPOSITION_CLIENT_CANDIDATE)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static tdm_error
 _tdm_sprd_display_prepare_commit(tdm_sprd_output_data *output_data) {
 
@@ -1201,7 +1222,10 @@ _tdm_sprd_display_prepare_commit(tdm_sprd_output_data *output_data) {
                _sprd_layer_attach_window(layer, output_data->target_hwc_window);
        }
 
-        /* set hwc windows */
+       if (_are_windows_with_client_candidate_type(&output_data->hwc_window_list))
+               return TDM_ERROR_NONE;
+
+       /* set hwc windows */
        LIST_FOR_EACH_ENTRY_REV(hw, &output_data->hwc_window_list, link) {
                if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
                        continue;
@@ -1803,6 +1827,7 @@ _sprd_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, td
 
        sprd_hwc_window->output_data = output;
        sprd_hwc_window->zpos = 0;
+       sprd_hwc_window->prev_validated_type = TDM_COMPOSITION_CLIENT;
 
        if (info)
                memcpy(&sprd_hwc_window->info, info, sizeof(tdm_hwc_window_info));
@@ -1856,6 +1881,8 @@ _comp_to_str(tdm_hwc_window_composition composition_type)
 {
        if (composition_type == TDM_COMPOSITION_CLIENT)
                return "CLIENT";
+       else if (composition_type == TDM_COMPOSITION_CLIENT_CANDIDATE)
+               return "CLIENT_CANDIDATE";
        else if (composition_type == TDM_COMPOSITION_DEVICE_CANDIDATE)
                return "DEVICE_CANDIDATE";
        else if (composition_type == TDM_COMPOSITION_DEVICE)
@@ -1886,6 +1913,87 @@ _get_number_of_visible_windows(tdm_sprd_output_data *sprd_output)
        return number;
 }
 
+static void
+_update_windows_previous_type(struct list_head *hwc_wnds)
+{
+       tdm_sprd_hwc_window_data *hw = NULL;
+
+       RETURN_VOID_IF_FAIL(hwc_wnds);
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP) {
+                       hw->prev_validated_type = TDM_COMPOSITION_CLIENT;
+                       continue;
+               }
+
+               hw->prev_validated_type = hw->validated_type;
+       }
+}
+
+static void
+_reset_windows_to_client(struct list_head *hwc_wnds)
+{
+       tdm_sprd_hwc_window_data *hw = NULL;
+
+       RETURN_VOID_IF_FAIL(hwc_wnds);
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               if (hw->prev_validated_type == TDM_COMPOSITION_DEVICE_CANDIDATE)
+                       hw->validated_type = TDM_COMPOSITION_CLIENT;
+
+               if (hw->prev_validated_type == TDM_COMPOSITION_CLIENT)
+                       hw->validated_type = TDM_COMPOSITION_CLIENT;
+
+               else if (hw->prev_validated_type == TDM_COMPOSITION_CLIENT_CANDIDATE)
+                       hw->validated_type = TDM_COMPOSITION_CLIENT_CANDIDATE;
+
+               else if (hw->prev_validated_type == TDM_COMPOSITION_DEVICE)
+                       hw->validated_type = TDM_COMPOSITION_CLIENT_CANDIDATE;
+
+               else if (hw->prev_validated_type == TDM_COMPOSITION_VIDEO)
+                       hw->validated_type = TDM_COMPOSITION_CLIENT_CANDIDATE;
+       }
+}
+
+/*
+ * If we got at least one device/video -> client transition or we still have at
+ * least one window at the client_candidate state we reset all windows
+ * to the client/client_candidate state as it's a reference implementation
+ * of the driver
+ */
+static int
+_is_reset_to_client_needed(struct list_head *hwc_wnds)
+{
+       tdm_sprd_hwc_window_data *hw = NULL;
+
+       RETURN_VAL_IF_FAIL(hwc_wnds, 0);
+
+       LIST_FOR_EACH_ENTRY(hw, hwc_wnds, link) {
+
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               /* client_type is kept, as a TDM_COMPOSITION_CLIENT_CANDIDATE, by the client(e20)
+                * till buffer (of this window) being composited to the fb_target */
+               if (hw->prev_validated_type == TDM_COMPOSITION_DEVICE &&
+                               hw->validated_type == TDM_COMPOSITION_CLIENT)
+                       return 1;
+
+               if (hw->prev_validated_type == TDM_COMPOSITION_VIDEO &&
+                               hw->validated_type == TDM_COMPOSITION_CLIENT)
+                       return 1;
+
+               if (hw->client_type == TDM_COMPOSITION_CLIENT_CANDIDATE)
+                       return 1;
+       }
+
+       return 0;
+}
+
 tdm_error
 sprd_output_hwc_validate(tdm_output *output, uint32_t *num_types)
 {
@@ -1898,7 +2006,7 @@ sprd_output_hwc_validate(tdm_output *output, uint32_t *num_types)
        int need_target_buffer = 0;
        int is_client_detected = 0;
        int max_hw_layer = HW_LAYER_NUM;
-       int i = 0;
+       int need_reset_wnds_to_client;
 
        sprd_data = sprd_output->sprd_data;
        RETURN_VAL_IF_FAIL(sprd_data != NULL, TDM_ERROR_INVALID_PARAMETER);
@@ -1966,15 +2074,24 @@ sprd_output_hwc_validate(tdm_output *output, uint32_t *num_types)
        if (is_client_detected)
                need_target_buffer = 1;
 
+       need_reset_wnds_to_client =
+                       _is_reset_to_client_needed(&sprd_output->hwc_window_list);
+
+       if (need_reset_wnds_to_client) {
+               _reset_windows_to_client(&sprd_output->hwc_window_list);
+
+               /* restore previous value */
+               need_target_buffer = sprd_output->need_target_buffer;
+       }
+
+       _update_windows_previous_type(&sprd_output->hwc_window_list);
+
        LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
                if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
                        continue;
 
-               if (need_target_buffer && hw_layer_count == i++)
-                       TDM_DBG(" window(%p) target", sprd_output->target_hwc_window);
-               else
-                       TDM_DBG(" window(%p) type: %s -> %s", hw,
-                                       _comp_to_str(hw->client_type), _comp_to_str(hw->validated_type));
+               TDM_DBG(" window(%p) type: %s -> %s", hw,
+                               _comp_to_str(hw->client_type), _comp_to_str(hw->validated_type));
        }
 
        sprd_output->need_target_buffer = need_target_buffer;