hwc: add support of HWC API 66/157366/17
authorRoman Marchenko <r.marchenko@samsung.com>
Thu, 29 Jun 2017 13:24:22 +0000 (16:24 +0300)
committerSooChan Lim <sc1.lim@samsung.com>
Wed, 1 Nov 2017 11:18:59 +0000 (11:18 +0000)
      add handlers of callback function:
       - sprd_output_hwc_window_create;
       - sprd_output_hwc_window_destroy;
       - sprd_output_validate;
       - sprd_output_get_changed_composition_types;
       - sprd_output_accept_changes;
       - sprd_output_get_target_surface_queue;
       - sprd_output_set_client_target_buffer;

       - sprd_hwc_window_get_tbm_surface_queue;
       - sprd_hwc_window_set_buffer;
       - sprd_hwc_window_set_composition_type;
       - sprd_hwc_window_set_info;
       - sprd_hwc_window_set_surface_damage;
       - sprd_hwc_window_set_zpos;

Change-Id: I6d8892ea2fe416fe5e306cb526a610a738289d40
Signed-off-by: Roman Marchenko <r.marchenko@samsung.com>
src/tdm_sprd.c
src/tdm_sprd.h
src/tdm_sprd_display.c

index 040441c..dcd5383 100755 (executable)
@@ -115,9 +115,11 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        tdm_func_display sprd_func_display;
        tdm_func_output sprd_func_output;
        tdm_func_layer sprd_func_layer;
+       tdm_func_hwc_window sprd_func_hwc_window;
        tdm_func_pp sprd_func_pp;
        tdm_func_capture sprd_func_capture;
        tdm_error ret;
+       char *str;
 
        if (!dpy) {
                TDM_ERR("display is null");
@@ -141,6 +143,10 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
                return NULL;
        }
 
+       str = getenv("TDM_HWC");
+       if (str)
+               sprd_data->hwc_mode = strtol(str, NULL, 10);
+
        LIST_INITHEAD(&sprd_data->output_list);
        LIST_INITHEAD(&sprd_data->buffer_list);
 
@@ -167,6 +173,29 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        sprd_func_output.output_set_mode = sprd_output_set_mode;
        sprd_func_output.output_get_mode = sprd_output_get_mode;
        sprd_func_output.output_create_capture = sprd_capture_create;
+       if (sprd_data->hwc_mode) {
+               sprd_func_output.output_hwc_create_window = sprd_output_hwc_window_create;
+               sprd_func_output.output_hwc_destroy_window = sprd_output_hwc_window_destroy;
+               sprd_func_output.output_hwc_validate = sprd_output_hwc_validate;
+               sprd_func_output.output_hwc_get_changed_composition_types = sprd_output_hwc_get_changed_composition_types;
+               sprd_func_output.output_hwc_accept_changes = sprd_output_hwc_accept_changes;
+               sprd_func_output.output_hwc_get_target_buffer_queue = sprd_output_hwc_get_target_buffer_queue;
+               sprd_func_output.output_hwc_set_client_target_buffer = sprd_output_hwc_set_client_target_buffer;
+       }
+
+       if (sprd_data->hwc_mode) {
+               memset(&sprd_func_hwc_window, 0, sizeof(sprd_func_hwc_window));
+               sprd_func_hwc_window.hwc_window_get_tbm_buffer_queue = sprd_hwc_window_get_tbm_buffer_queue;
+               sprd_func_hwc_window.hwc_window_set_buffer = sprd_hwc_window_set_buffer;
+               sprd_func_hwc_window.hwc_window_set_composition_type = sprd_hwc_window_set_composition_type;
+               sprd_func_hwc_window.hwc_window_set_info = sprd_hwc_window_set_info;
+               sprd_func_hwc_window.hwc_window_set_buffer_damage = sprd_hwc_window_set_buffer_damage;
+               sprd_func_hwc_window.hwc_window_set_zpos = sprd_hwc_window_set_zpos;
+               sprd_func_hwc_window.hwc_window_set_flags = sprd_hwc_window_set_flags;
+               sprd_func_hwc_window.hwc_window_unset_flags = sprd_hwc_window_unset_flags;
+               sprd_func_hwc_window.hwc_window_video_get_capability = sprd_hwc_window_video_get_capability;
+               sprd_func_hwc_window.hwc_window_video_get_supported_format = sprd_hwc_window_video_get_supported_format;
+       }
 
        memset(&sprd_func_layer, 0, sizeof(sprd_func_layer));
        sprd_func_layer.layer_get_capability = sprd_layer_get_capability;
@@ -204,6 +233,13 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        if (ret != TDM_ERROR_NONE)
                goto failed_l;
 
+       if (sprd_data->hwc_mode) {
+               ret = tdm_backend_register_func_hwc_window(dpy, &sprd_func_hwc_window);
+               if (ret != TDM_ERROR_NONE)
+                       goto failed_l;
+       }
+
+
        ret = tdm_backend_register_func_pp(dpy, &sprd_func_pp);
        if (ret != TDM_ERROR_NONE)
                goto failed_l;
@@ -263,7 +299,7 @@ failed_l:
 tdm_backend_module tdm_backend_module_data = {
        "sprd",
        "Samsung",
-       TDM_BACKEND_SET_ABI_VERSION(1, 1),
+       TDM_BACKEND_ABI_VERSION,
        tdm_sprd_init,
        tdm_sprd_deinit
 };
index 1903c92..41971c9 100644 (file)
@@ -16,6 +16,7 @@
 #include <xf86drm.h>
 #include <tbm_surface.h>
 #include <tbm_surface_internal.h>
+#include <tbm_surface_queue.h>
 #include <tdm_backend.h>
 #include <tdm_log.h>
 #include <tdm_list.h>
@@ -39,6 +40,16 @@ tdm_error    sprd_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value
 tdm_error    sprd_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value);
 tdm_error    sprd_output_set_mode(tdm_output *output, const tdm_output_mode *mode);
 tdm_error    sprd_output_get_mode(tdm_output *output, const tdm_output_mode **mode);
+tdm_hwc_window * sprd_output_hwc_window_create(tdm_output *output, tdm_error *error);
+tdm_error    sprd_output_hwc_window_destroy(tdm_output *output, tdm_hwc_window *hwc_window);
+tdm_error    sprd_output_hwc_validate(tdm_output *output, uint32_t *num_types);
+tdm_error    sprd_output_hwc_get_changed_composition_types(tdm_output *output, uint32_t *num_elements,
+                                                                                tdm_hwc_window **hwc_window,
+                                                                                tdm_hwc_window_composition *composition_types);
+tdm_error    sprd_output_hwc_accept_changes(tdm_output *output);
+tbm_surface_queue_h sprd_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error);
+tdm_error    sprd_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
+                                                                       tdm_hwc_region damage);
 tdm_error    sprd_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
 tdm_error    sprd_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value);
 tdm_error    sprd_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value);
@@ -47,6 +58,21 @@ tdm_error    sprd_layer_get_info(tdm_layer *layer, tdm_info_layer *info);
 tdm_error    sprd_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer);
 tdm_error    sprd_layer_unset_buffer(tdm_layer *layer);
 tdm_error    sprd_layer_get_buffer_flags(tdm_layer *layer, unsigned int *flags);
+tdm_error    sprd_hwc_window_video_get_capability(tdm_hwc_window *hwc_window,
+                                                                                                 tdm_hwc_window_video_capability *video_capability);
+tdm_error    sprd_hwc_window_video_get_supported_format(tdm_hwc_window *hwc_window,
+                                                                                                               const tbm_format **formats,
+                                                                                                               int *count);
+tbm_surface_queue_h sprd_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error);
+tdm_error    sprd_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos);
+tdm_error    sprd_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
+                                                                                               tdm_hwc_window_composition composition_type);
+tdm_error    sprd_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage);
+tdm_error    sprd_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info);
+tdm_error    sprd_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface);
+tdm_error    sprd_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags);
+tdm_error    sprd_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags);
+
 void         sprd_pp_destroy(tdm_pp *pp);
 tdm_error    sprd_pp_set_info(tdm_pp *pp, tdm_info_pp *info);
 tdm_error    sprd_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
@@ -110,6 +136,8 @@ typedef struct _tdm_sprd_data {
        int drm_fd;
        int output_count;
 
+       int hwc_mode;
+
        struct list_head output_list;
        struct list_head buffer_list;
 
index 79ab300..bbb2f38 100644 (file)
@@ -4,8 +4,10 @@
 
 #include <tdm_helper.h>
 #include <linux/fb.h>
+#include <drm.h>
 #include <video/sprdfb.h>
 #include <tbm_surface.h>
+#include <tbm_surface_queue.h>
 #include "tdm_sprd.h"
 
 #define MIN_WIDTH   32
@@ -17,8 +19,17 @@ typedef struct drm_event hw_event_t;
 
 #define FB_DEV_LCD  "/dev/fb0"
 
+#define HW_LAYER_NUM  2
+
+#define LIST_INSERT_AFTER(__after, __item) \
+               (__item)->prev = (__after); \
+               (__item)->next = (__after)->next; \
+               (__after)->next->prev = (__item); \
+               (__after)->next = (__item);
+
 typedef struct _tdm_sprd_output_data tdm_sprd_output_data;
 typedef struct _tdm_sprd_layer_data tdm_sprd_layer_data;
+typedef struct _tdm_sprd_hwc_window_data tdm_sprd_hwc_window_data;
 typedef struct _tdm_sprd_vblank_data_s tdm_sprd_vblank_data;
 
 typedef enum {
@@ -81,7 +92,13 @@ struct _tdm_sprd_output_data {
 
        tdm_output_dpms dpms_value;
 
+       tdm_sprd_hwc_window_data *target_hwc_window;
+
+       int need_validate;
+       int need_target_buffer;
+
        struct list_head capture_list;
+       struct list_head hwc_window_list;
 };
 
 struct _tdm_sprd_layer_data {
@@ -103,11 +120,36 @@ struct _tdm_sprd_layer_data {
 
        tdm_sprd_display_buffer *display_buffer;
        int display_buffer_changed;
-       // current hw overlay setting
+       /* current hw overlay setting */
        overlay_info ovi;
        int enabled_flag;
 };
 
+struct _tdm_sprd_hwc_window_data {
+       struct list_head link;
+
+       /* data which are fixed at initializing */
+       tdm_sprd_data *sprd_data;
+       tdm_sprd_output_data *output_data;
+
+       /* not fixed data below */
+       int zpos;
+
+       tdm_hwc_window_info info;
+       int info_changed;
+
+       tdm_sprd_display_buffer *display_buffer;
+       int display_buffer_changed;
+       int enabled_flag;
+
+       /* client_type stores the initial type given to us by client(compositor) */
+       tdm_hwc_window_composition client_type;
+       /* validated_type stores the type after running Validate */
+       tdm_hwc_window_composition validated_type;
+
+       tdm_hwc_window_flag flags;
+};
+
 typedef struct _Drm_Event_Context {
        void (*vblank_handler)(int fd, unsigned int sequence, unsigned int tv_sec,
                                                        unsigned int tv_usec, void *user_data);
@@ -126,6 +168,17 @@ tbm_format osd_layer_formats[] = {
        TBM_FORMAT_ARGB8888
 };
 
+tbm_format hwc_window_video_formats[] = {
+       TBM_FORMAT_RGB565,
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_NV12,
+       TBM_FORMAT_YUV420
+};
+
+tdm_hwc_window * _sprd_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, tdm_error *error);
+
+
 #if 0
 static tdm_error
 check_hw_restriction(unsigned int output_w, unsigned int buf_w,
@@ -426,6 +479,27 @@ _tdm_sprd_tbmformat_to_sprdformat(int tbm_format, overlay_info *ovi)
 }
 
 static tdm_error
+_sprd_layer_attach_window(tdm_sprd_layer_data *layer_data, tdm_sprd_hwc_window_data *hwc_window_data)
+{
+       tdm_error ret = TDM_ERROR_NONE;
+
+       RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED);
+       RETURN_VAL_IF_FAIL(hwc_window_data, TDM_ERROR_OPERATION_FAILED);
+
+       if (hwc_window_data == NULL || hwc_window_data->display_buffer == NULL) {
+               ret = sprd_layer_unset_buffer(layer_data);
+               RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+       } else {
+               ret = sprd_layer_set_info((tdm_layer *)layer_data, (tdm_info_layer *)&(hwc_window_data->info));
+               RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+               RETURN_VAL_IF_FAIL(hwc_window_data->display_buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
+               ret = sprd_layer_set_buffer(layer_data, hwc_window_data->display_buffer->buffer);
+               RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+       }
+       return ret;
+}
+
+static tdm_error
 _tdm_sprd_display_do_commit(tdm_sprd_output_data *output_data)
 {
        tdm_error res = TDM_ERROR_NONE;
@@ -788,6 +862,8 @@ _tdm_sprd_display_create_output_LCD(tdm_sprd_data *sprd_data)
                return NULL;
        }
        LIST_INITHEAD(&output_data->capture_list);
+       if (sprd_data->hwc_mode)
+               LIST_INITHEAD(&output_data->hwc_window_list);
        return output_data;
 }
 
@@ -932,6 +1008,19 @@ sprd_display_create_pp(tdm_backend_data *bdata, tdm_error *error)
        return tdm_sprd_pp_create(sprd_data, error);
 }
 
+tdm_sprd_layer_data *
+_sprd_output_get_layer(tdm_sprd_output_data *output_data, int index)
+{
+       RETURN_VAL_IF_FAIL(output_data, NULL);
+
+       tdm_sprd_layer_data *l = NULL;
+       LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link)
+               if (l->zpos == index)
+                       return l;
+       return NULL;
+}
+
+
 tdm_error
 sprd_output_get_capability(tdm_output *output, tdm_caps_output *caps)
 {
@@ -991,6 +1080,13 @@ sprd_output_get_layers(tdm_output *output, int *count, tdm_error *error)
        RETURN_VAL_IF_FAIL(output_data, NULL);
        RETURN_VAL_IF_FAIL(count, NULL);
 
+       if (output_data->sprd_data->hwc_mode) {
+               TDM_INFO("layers aren't supported in HWC mode");
+               *count = 0;
+               ret = TDM_ERROR_NONE;
+               goto failed_get;
+       }
+
        *count = 0;
        LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
                (*count)++;
@@ -1085,6 +1181,43 @@ sprd_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler fun
        return TDM_ERROR_NONE;
 }
 
+static tdm_error
+_tdm_sprd_display_prepare_commit(tdm_sprd_output_data *output_data) {
+
+       tdm_sprd_layer_data * layer = NULL;
+       int i = HW_LAYER_NUM-1;
+       tdm_sprd_hwc_window_data *hw = NULL;
+
+       RETURN_VAL_IF_FAIL(output_data->need_validate == 0, TDM_ERROR_OPERATION_FAILED);
+
+       /* set target hwc window */
+       if (output_data->need_target_buffer) {
+               layer = _sprd_output_get_layer(output_data, i--);
+               _sprd_layer_attach_window(layer, output_data->target_hwc_window);
+       }
+
+        /* set hwc windows */
+       LIST_FOR_EACH_ENTRY_REV(hw, &output_data->hwc_window_list, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+               if (hw->client_type != TDM_COMPOSITION_DEVICE && hw->client_type != TDM_COMPOSITION_VIDEO)
+                       continue;
+               if (i < 0)
+                       return TDM_ERROR_OPERATION_FAILED;
+               layer = _sprd_output_get_layer(output_data, i--);
+               _sprd_layer_attach_window(layer, hw);
+       }
+
+       /* disable unused layer */
+       while (i >= 0) {
+               layer = _sprd_output_get_layer(output_data, i--);
+               _sprd_layer_attach_window(layer, NULL);
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+
 tdm_error
 sprd_output_commit(tdm_output *output, int sync, void *user_data)
 {
@@ -1096,7 +1229,13 @@ sprd_output_commit(tdm_output *output, int sync, void *user_data)
 
        sprd_data = output_data->sprd_data;
 
+       if (sprd_data->hwc_mode) {
+               ret = _tdm_sprd_display_prepare_commit(output_data);
+               RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+       }
+
        _tdm_sprd_display_do_commit(output_data);
+       RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
 
        tdm_sprd_vblank_data *vblank_data = calloc(1, sizeof(tdm_sprd_vblank_data));
        uint target_msc;
@@ -1181,6 +1320,31 @@ sprd_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
 
        RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
        RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(output_data->sprd_data, TDM_ERROR_INVALID_PARAMETER);
+
+       if (output_data->sprd_data->hwc_mode) {
+
+               tdm_hwc_window_info info = {0};
+               tdm_error ret = TDM_ERROR_NONE;
+               tdm_sprd_hwc_window_data * target_hwc_window;
+
+               info.src_config.pos.h = mode->vdisplay;
+               info.src_config.pos.w = mode->hdisplay;
+               info.src_config.size.h = mode->hdisplay;
+               info.src_config.size.v = mode->vdisplay;
+               info.src_config.format = TBM_FORMAT_ARGB8888;
+
+               target_hwc_window = _sprd_output_hwc_window_create(output_data, &info, &ret);
+               if (ret != TDM_ERROR_NONE)  {
+                       TDM_ERR("create target hwc window failed (%d)", ret);
+                       return TDM_ERROR_OPERATION_FAILED;
+               }
+
+               if (output_data->target_hwc_window)
+                       sprd_output_hwc_window_destroy(output, output_data->target_hwc_window);
+
+               output_data->target_hwc_window = target_hwc_window;
+       }
 
        output_data->current_mode = mode;
        output_data->mode_changed = 1;
@@ -1273,6 +1437,71 @@ sprd_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
        return TDM_ERROR_NONE;
 }
 
+tdm_sprd_display_buffer *
+_tdm_sprd_display_creat_buffer(tdm_sprd_data *sprd_data, tbm_surface_h surface, tdm_error * err)
+{
+       int i, count;
+       int bw, bh;
+       tdm_sprd_display_buffer * display_buffer = NULL;
+       tdm_error res = TDM_ERROR_NONE;
+
+       RETURN_VAL_IF_FAIL(sprd_data, NULL);
+       RETURN_VAL_IF_FAIL(surface, NULL);
+
+       display_buffer = calloc(1, sizeof(tdm_sprd_display_buffer));
+       if (!display_buffer) {
+               if (err)
+                       *err = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       display_buffer->buffer = surface;
+
+       res = tdm_buffer_add_destroy_handler(surface, _tdm_sprd_display_cb_destroy_buffer, sprd_data);
+       if (res != TDM_ERROR_NONE) {
+               if (err)
+                       *err = res;
+               TDM_ERR("add destroy handler fail");
+               free(display_buffer);
+               return NULL;
+       }
+
+       tdm_helper_get_buffer_full_size(surface, &bw, &bh);
+
+       display_buffer->width = bw;
+       display_buffer->height = bh;
+       display_buffer->format = tbm_surface_get_format(surface);
+       display_buffer->count = tbm_surface_internal_get_num_bos(surface);
+       count = tbm_surface_internal_get_num_planes(display_buffer->format);
+       TDM_DBG("create buffer: %dx%d %c%c%c%c bo_num:%d plane_num:%d",
+                       display_buffer->width, display_buffer->height, FOURCC_STR(display_buffer->format),
+                       display_buffer->count, count);
+
+       for (i = 0; i < display_buffer->count; i++) {
+               tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
+               display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+               display_buffer->name[i] = tbm_bo_export(bo);
+               TDM_DBG("    create buffer: bo%d(name:%d handle:%d)", i, display_buffer->name[i],
+                               display_buffer->handles[i]);
+       }
+       for (i = 0; i < count; i++) {
+               tbm_surface_internal_get_plane_data(surface, i, &display_buffer->size, &display_buffer->offsets[i],
+                                                                                               &display_buffer->pitches[i]);
+               TDM_DBG("    create buffer: plane%d(size:%d offset:%d pitch:%d)", i, display_buffer->size,
+                               display_buffer->offsets[i], display_buffer->pitches[i]);
+       }
+
+       if (IS_RGB(display_buffer->format))
+               display_buffer->width = display_buffer->pitches[0] >> 2;
+       else
+               display_buffer->width = display_buffer->pitches[0];
+
+       if (err)
+               *err = TDM_ERROR_NONE;
+
+       return display_buffer;
+}
+
 tdm_error
 sprd_layer_set_buffer(tdm_layer *layer, tbm_surface_h surface)
 {
@@ -1280,7 +1509,6 @@ sprd_layer_set_buffer(tdm_layer *layer, tbm_surface_h surface)
        tdm_sprd_data *sprd_data;
        tdm_sprd_display_buffer *display_buffer;
        tdm_error err = TDM_ERROR_NONE;
-       int i, count;
 
        RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
        RETURN_VAL_IF_FAIL(surface, TDM_ERROR_INVALID_PARAMETER);
@@ -1288,53 +1516,9 @@ sprd_layer_set_buffer(tdm_layer *layer, tbm_surface_h surface)
        sprd_data = layer_data->sprd_data;
        display_buffer = _tdm_sprd_display_find_buffer(sprd_data, surface);
        if (!display_buffer) {
-               int bw, bh;
-
-               display_buffer = calloc(1, sizeof(tdm_sprd_display_buffer));
-               if (!display_buffer) {
-                       TDM_ERR("alloc failed");
-                       return TDM_ERROR_OUT_OF_MEMORY;
-               }
-               display_buffer->buffer = surface;
-
-               err = tdm_buffer_add_destroy_handler(surface, _tdm_sprd_display_cb_destroy_buffer, sprd_data);
-               if (err != TDM_ERROR_NONE) {
-                       TDM_ERR("add destroy handler fail");
-                       free(display_buffer);
-                       return TDM_ERROR_OPERATION_FAILED;
-               }
+               display_buffer = _tdm_sprd_display_creat_buffer(sprd_data, surface, &err);
+               RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
                LIST_ADDTAIL(&display_buffer->link, &sprd_data->buffer_list);
-
-               tdm_helper_get_buffer_full_size(surface, &bw, &bh);
-
-               display_buffer->width = bw;
-               display_buffer->height = bh;
-               display_buffer->format = tbm_surface_get_format(surface);
-               display_buffer->count = tbm_surface_internal_get_num_bos(surface);
-               count = tbm_surface_internal_get_num_planes(display_buffer->format);
-               TDM_DBG("set buffer layer(0x%x): %dx%d %c%c%c%c bo_num:%d plane_num:%d", layer_data->capabilities,
-                               display_buffer->width, display_buffer->height, FOURCC_STR(display_buffer->format),
-                               display_buffer->count, count);
-
-               for (i = 0; i < display_buffer->count; i++) {
-                       tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
-                       display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
-                       display_buffer->name[i] = tbm_bo_export(bo);
-                       TDM_DBG("    set buffer layer(0x%x): bo%d(name:%d handle:%d)", layer_data->capabilities, i,
-                                       display_buffer->name[i], display_buffer->handles[i]);
-               }
-               for (i = 0; i < count; i++) {
-                       tbm_surface_internal_get_plane_data(surface, i, &display_buffer->size, &display_buffer->offsets[i],
-                                                                                                       &display_buffer->pitches[i]);
-                       TDM_DBG("    set buffer layer(0x%x): plane%d(size:%d offset:%d pitch:%d)", layer_data->capabilities, i,
-                                       display_buffer->size, display_buffer->offsets[i], display_buffer->pitches[i]);
-
-               }
-
-               if (IS_RGB(display_buffer->format))
-                       display_buffer->width = display_buffer->pitches[0] >> 2;
-               else
-                       display_buffer->width = display_buffer->pitches[0];
        }
 
        layer_data->display_buffer = display_buffer;
@@ -1460,6 +1644,8 @@ tdm_error
 sprd_output_attach_capture(tdm_output *output, tdm_capture *capture)
 {
        RETURN_VAL_IF_FAIL(output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(capture, TDM_ERROR_INVALID_PARAMETER);
+
        tdm_sprd_output_capture_data *output_capture_data_p =
                                                                        calloc(1, sizeof(tdm_sprd_output_capture_data));
        RETURN_VAL_IF_FAIL(output_capture_data_p, TDM_ERROR_OUT_OF_MEMORY);
@@ -1474,6 +1660,8 @@ void
 sprd_output_dettach_capture(tdm_output *output, tdm_capture *capture)
 {
        RETURN_VOID_IF_FAIL(output);
+       RETURN_VOID_IF_FAIL(capture);
+
        tdm_sprd_output_data *output_data = output;
        if (!LIST_IS_EMPTY(&output_data->capture_list)) {
                tdm_sprd_output_capture_data *l = NULL, *ll = NULL;
@@ -1513,3 +1701,592 @@ sprd_layer_get_zpos(tdm_layer *layer, int *zpos)
        }
        return TDM_ERROR_NONE;
 }
+
+static int
+_sprd_layer_is_supported_format(tdm_sprd_layer_data *layer_data, tbm_format format)
+{
+       RETURN_VAL_IF_FAIL(layer_data, 0);
+       return IS_RGB(format);
+}
+
+static int
+_sprd_hwc_window_is_reserved_buffer(tdm_sprd_hwc_window_data *hwc_window) {
+       tbm_bo bo = NULL;
+       int falgs = 0;
+
+       RETURN_VAL_IF_FAIL(hwc_window != NULL, 0);
+       RETURN_VAL_IF_FAIL(hwc_window->display_buffer != NULL, 0);
+
+       bo = tbm_surface_internal_get_bo(hwc_window->display_buffer->buffer, 0);
+       RETURN_VAL_IF_FAIL(bo != NULL, 0);
+
+       falgs = tbm_bo_get_flags(bo);
+
+       return falgs & TBM_BO_SCANOUT;
+}
+
+tdm_error
+_sprd_output_insert_hwc_window(tdm_sprd_output_data *output, tdm_sprd_hwc_window_data *hwc_window)
+{
+
+       RETURN_VAL_IF_FAIL(output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(hwc_window, TDM_ERROR_INVALID_PARAMETER);
+
+       tdm_sprd_hwc_window_data *item = NULL;
+       LIST_FOR_EACH_ENTRY_REV(item, &output->hwc_window_list, link) {
+
+               if (item == hwc_window)
+                       return TDM_ERROR_OPERATION_FAILED;
+
+               if (item->zpos <= hwc_window->zpos)
+                       break;
+       }
+
+       LIST_INSERT_AFTER(&item->link, &hwc_window->link);
+
+       return TDM_ERROR_NONE;
+}
+
+int
+_sprd_output_get_changed_number(tdm_sprd_output_data *sprd_output)
+{
+       int num = 0;
+       tdm_sprd_hwc_window_data *hw = NULL;
+
+       RETURN_VAL_IF_FAIL(sprd_output, TDM_ERROR_INVALID_PARAMETER);
+
+       LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               if (hw->client_type != hw->validated_type)
+                       num++;
+       }
+       return num;
+}
+
+tdm_hwc_window *
+_sprd_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, tdm_error *error)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = NULL;
+       tdm_sprd_output_data *sprd_output = output;
+
+       if (error)
+               *error = TDM_ERROR_NONE;
+
+       if (!sprd_output) {
+               TDM_ERR("invalid params");
+               if (error)
+                       *error = TDM_ERROR_INVALID_PARAMETER;
+               return NULL;
+       }
+
+       sprd_hwc_window = calloc(1, sizeof(tdm_sprd_hwc_window_data));
+       if (!sprd_hwc_window) {
+               TDM_ERR("alloc failed");
+               if (error)
+                       *error = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       if ((sprd_hwc_window->sprd_data = sprd_output_get_sprd_data(output)) == NULL) {
+               TDM_ERR("invalid params");
+               if (error)
+                       *error = TDM_ERROR_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       sprd_hwc_window->output_data = output;
+       sprd_hwc_window->zpos = 0;
+
+       if (info)
+               memcpy(&sprd_hwc_window->info, info, sizeof(tdm_hwc_window_info));
+
+       LIST_INITHEAD(&sprd_hwc_window->link);
+
+       return sprd_hwc_window;
+fail:
+       if (sprd_hwc_window)
+               free(sprd_hwc_window);
+       return NULL;
+}
+
+tdm_hwc_window *
+sprd_output_hwc_window_create(tdm_output *output, tdm_error *error)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = NULL;
+       tdm_sprd_output_data *sprd_output = output;
+
+       RETURN_VAL_IF_FAIL(sprd_output, NULL);
+
+       sprd_hwc_window = _sprd_output_hwc_window_create(sprd_output, NULL, error);
+       RETURN_VAL_IF_FAIL(sprd_hwc_window, NULL);
+
+       _sprd_output_insert_hwc_window(sprd_output, sprd_hwc_window);
+
+       TDM_DBG("hwc_window(%p) create", sprd_hwc_window);
+       if (error)
+               *error = TDM_ERROR_NONE;
+
+       return sprd_hwc_window;
+}
+
+tdm_error
+sprd_output_hwc_window_destroy(tdm_output *output, tdm_hwc_window *hwc_window)
+{
+       RETURN_VAL_IF_FAIL(output, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(hwc_window, TDM_ERROR_INVALID_PARAMETER);
+
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+       LIST_DEL(&sprd_hwc_window->link);
+
+       free(sprd_hwc_window);
+
+       return TDM_ERROR_NONE;
+}
+
+static const char *
+_comp_to_str(tdm_hwc_window_composition composition_type)
+{
+       if (composition_type == TDM_COMPOSITION_CLIENT)
+               return "CLIENT";
+       else if (composition_type == TDM_COMPOSITION_DEVICE_CANDIDATE)
+               return "DEVICE_CANDIDATE";
+       else if (composition_type == TDM_COMPOSITION_DEVICE)
+               return "DEVICE";
+       else if (composition_type == TDM_COMPOSITION_CURSOR)
+               return "CURSOR";
+       else if (composition_type == TDM_COMPOSITION_VIDEO)
+               return "VIDEO";
+
+       return "unknown";
+}
+
+static int
+_get_number_of_visible_windows(tdm_sprd_output_data *sprd_output)
+{
+       int number = 0;
+       tdm_sprd_hwc_window_data *window = NULL;
+
+       RETURN_VAL_IF_FAIL(sprd_output, 0);
+
+       LIST_FOR_EACH_ENTRY(window, &sprd_output->hwc_window_list, link) {
+               if (window->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               number++;
+       }
+
+       return number;
+}
+
+tdm_error
+sprd_output_hwc_validate(tdm_output *output, uint32_t *num_types)
+{
+       tdm_sprd_output_data *sprd_output = output;
+       tdm_sprd_data *sprd_data = NULL;
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
+       tdm_sprd_hwc_window_data *hw = NULL;
+       int hw_layer_count = 0;
+       int need_target_buffer = 0;
+       int is_client_detected = 0;
+       int max_hw_layer = HW_LAYER_NUM;
+       int i = 0;
+
+       sprd_data = sprd_output->sprd_data;
+       RETURN_VAL_IF_FAIL(sprd_data != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       tdm_sprd_layer_data * layer = NULL;
+
+       if (_get_number_of_visible_windows(sprd_output) > max_hw_layer)
+               need_target_buffer = 1;
+
+       is_client_detected = 0;
+       /* check client_type */
+       LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               if ((hw->client_type == TDM_COMPOSITION_DEVICE || hw->client_type == TDM_COMPOSITION_VIDEO)
+                       && !is_client_detected) {
+                       hw->validated_type = TDM_COMPOSITION_DEVICE_CANDIDATE;
+               } else {
+                       hw->validated_type = TDM_COMPOSITION_CLIENT;
+                       need_target_buffer = 1;
+                       is_client_detected = 1;
+               }
+       }
+
+       if (need_target_buffer)
+               max_hw_layer--;
+
+       is_client_detected = 0;
+       /* check format and flags for DEVICE_CANDIDATE */
+       LIST_FOR_EACH_ENTRY(hw, &sprd_output->hwc_window_list, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               if (hw->validated_type == TDM_COMPOSITION_DEVICE_CANDIDATE) {
+                       if (is_client_detected || hw_layer_count >= max_hw_layer) {
+                               is_client_detected = 1;
+                               hw->validated_type = TDM_COMPOSITION_CLIENT;
+                       } else {
+                               if (hw->client_type == TDM_COMPOSITION_VIDEO && hw_layer_count == 0 &&
+                                       _sprd_hwc_window_is_reserved_buffer(hw)) {
+                                       hw_layer_count++;
+                                       hw->validated_type = TDM_COMPOSITION_VIDEO;
+                                       continue;
+
+                               }
+                               layer = _sprd_output_get_layer(sprd_output, hw_layer_count);
+                               /* check format */
+                               if (!_sprd_layer_is_supported_format(layer, hw->info.src_config.format))
+                                       hw->validated_type = TDM_COMPOSITION_CLIENT;
+                               else if (!hw->display_buffer || !hw->display_buffer->buffer)
+                                       hw->validated_type = TDM_COMPOSITION_CLIENT;
+                               /* check buffer flags */
+                               else if (_sprd_hwc_window_is_reserved_buffer(hw)) {
+                                       hw_layer_count++;
+                                       hw->validated_type = TDM_COMPOSITION_DEVICE;
+                                       continue;
+
+                               }
+                               is_client_detected = 1;
+                       }
+               }
+       }
+
+       if (is_client_detected)
+               need_target_buffer = 1;
+
+       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));
+       }
+
+       sprd_output->need_target_buffer = need_target_buffer;
+
+       *num_types = _sprd_output_get_changed_number(sprd_output);
+
+       if (*num_types == 0)
+               sprd_output->need_validate = 0;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_output_hwc_get_changed_composition_types(tdm_output *output,
+                                                                                uint32_t *num_elements,
+                                                                                tdm_hwc_window **hwc_window,
+                                                                                tdm_hwc_window_composition *composition_types)
+{
+       tdm_sprd_output_data *sprd_output = output;
+       int num = 0;
+
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       if ((hwc_window == NULL) || (composition_types == NULL)) {
+               *num_elements = _sprd_output_get_changed_number(sprd_output);
+               return TDM_ERROR_NONE;
+       }
+
+       tdm_sprd_hwc_window_data *hw = NULL;
+       LIST_FOR_EACH_ENTRY_REV(hw, &sprd_output->hwc_window_list, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               if (num >= *num_elements)
+                       break;
+
+               if (hw->client_type != hw->validated_type) {
+                       composition_types[num] = hw->validated_type;
+                       hwc_window[num] = hw;
+                       num++;
+               }
+       }
+
+       /* set real num of changed composition types */
+       *num_elements = num;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_output_hwc_accept_changes(tdm_output *output)
+{
+       tdm_sprd_output_data *sprd_output = output;
+
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       tdm_sprd_hwc_window_data *hw = NULL;
+       LIST_FOR_EACH_ENTRY_REV(hw, &sprd_output->hwc_window_list, link) {
+               if (hw->flags & TDM_HWC_WINDOW_FLAG_SKIP)
+                       continue;
+
+               hw->client_type = hw->validated_type;
+       }
+
+       sprd_output->need_validate = 0;
+
+       return TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+sprd_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error)
+{
+       tdm_sprd_output_data *sprd_output = output;
+       tbm_surface_queue_h tqueue = NULL;
+
+       if (error)
+               *error = TDM_ERROR_INVALID_PARAMETER;
+
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, NULL);
+
+       if (sprd_output->target_hwc_window == NULL) {
+               if (error)
+                       *error = TDM_ERROR_OPERATION_FAILED;
+               return NULL;
+       }
+
+       tqueue = sprd_hwc_window_get_tbm_buffer_queue(sprd_output->target_hwc_window, error);
+       RETURN_VAL_IF_FAIL(tqueue, NULL);
+
+       if (error)
+               *error = TDM_ERROR_NONE;
+       return tqueue;
+}
+
+tdm_error
+sprd_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
+                                                                       tdm_hwc_region damage)
+{
+       tdm_sprd_output_data *sprd_output = output;
+       tdm_error err;
+
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(sprd_output->target_hwc_window  != NULL, TDM_ERROR_OPERATION_FAILED);
+
+       err = sprd_hwc_window_set_buffer(sprd_output->target_hwc_window, buffer);
+       RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
+
+       err = sprd_hwc_window_set_buffer_damage(sprd_output->target_hwc_window, damage);
+       RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
+
+       return TDM_ERROR_NONE;
+}
+
+tbm_surface_queue_h
+sprd_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = NULL;
+       tdm_sprd_output_data *sprd_output = NULL;
+       tbm_surface_queue_h tqueue = NULL;
+
+       if (error)
+               *error = TDM_ERROR_INVALID_PARAMETER;
+
+       RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
+       sprd_hwc_window = hwc_window;
+       sprd_output = sprd_hwc_window->output_data;
+
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, NULL);
+
+       int wight = sprd_hwc_window->info.src_config.size.h;
+       int hight = sprd_hwc_window->info.src_config.size.v;
+       tbm_format format = sprd_hwc_window->info.src_config.format;
+
+       tqueue = tbm_surface_queue_create(3, wight, hight, format, TBM_BO_SCANOUT);
+       if (error)
+               *error = TDM_ERROR_OPERATION_FAILED;
+       RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
+
+       if (error)
+               *error = TDM_ERROR_NONE;
+       return tqueue;
+
+}
+
+tdm_error
+sprd_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+       tdm_sprd_output_data *sprd_output;
+
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(zpos < 256, TDM_ERROR_INVALID_PARAMETER);
+
+       sprd_output = sprd_hwc_window->output_data;
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       if (sprd_hwc_window->zpos == zpos)
+               return TDM_ERROR_NONE;
+
+       LIST_DEL(&sprd_hwc_window->link);
+
+       sprd_hwc_window->zpos = zpos;
+
+       _sprd_output_insert_hwc_window(sprd_output, sprd_hwc_window);
+
+       sprd_output->need_validate = 1;
+
+       return TDM_ERROR_NONE;
+
+}
+
+tdm_error
+sprd_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
+                                                                       tdm_hwc_window_composition comp_type)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+       tdm_sprd_output_data *sprd_output = sprd_hwc_window->output_data;
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       if (sprd_hwc_window->client_type == comp_type)
+               return TDM_ERROR_NONE;
+
+       sprd_hwc_window->client_type = comp_type;
+       sprd_output->need_validate = 1;
+
+       return TDM_ERROR_NONE;
+
+}
+
+tdm_error
+sprd_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+       tdm_sprd_output_data *sprd_output = sprd_hwc_window->output_data;
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       //TODO::
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+       tdm_sprd_output_data *sprd_output = sprd_hwc_window->output_data;
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       if (memcmp(&sprd_hwc_window->info, info, sizeof(tdm_hwc_window_info)) == 0)
+               return TDM_ERROR_NONE;
+
+       sprd_hwc_window->info = *info;
+       sprd_output->need_validate = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+       tdm_sprd_output_data *sprd_output;
+       tdm_sprd_data *sprd_data;
+       tdm_error err = TDM_ERROR_OPERATION_FAILED;
+
+       tdm_sprd_display_buffer *display_buffer = NULL;
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, err);
+
+       sprd_output = sprd_hwc_window->output_data;
+       sprd_data = sprd_hwc_window->sprd_data;
+
+       RETURN_VAL_IF_FAIL(sprd_output != NULL, err);
+       RETURN_VAL_IF_FAIL(sprd_data != NULL, err);
+
+       if (!surface) {
+               sprd_hwc_window->display_buffer = NULL;
+               return TDM_ERROR_NONE;
+       }
+
+       display_buffer = _tdm_sprd_display_find_buffer(sprd_data, surface);
+       if (!display_buffer) {
+               display_buffer = _tdm_sprd_display_creat_buffer(sprd_data, surface, &err);
+               RETURN_VAL_IF_FAIL(display_buffer != NULL, err);
+               LIST_ADDTAIL(&display_buffer->link, &sprd_data->buffer_list);
+       }
+
+       if (sprd_hwc_window->display_buffer == display_buffer)
+               return TDM_ERROR_NONE;
+
+       sprd_hwc_window->display_buffer = display_buffer;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       sprd_hwc_window->flags |= flags;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+       RETURN_VAL_IF_FAIL(sprd_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       sprd_hwc_window->flags &= ~flags;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_video_get_capability(tdm_hwc_window *hwc_window,
+                                                                          tdm_hwc_window_video_capability *video_capability)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+       RETURN_VAL_IF_FAIL(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(video_capability != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(sprd_hwc_window->validated_type == TDM_COMPOSITION_VIDEO, TDM_ERROR_INVALID_PARAMETER);
+
+       *video_capability = TDM_HWC_WINDOW_VIDEO_CAPABILITY_SCANOUT;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_hwc_window_video_get_supported_format(tdm_hwc_window *hwc_window,
+                                                                                        const tbm_format **formats,
+                                                                                        int *count)
+{
+       tdm_sprd_hwc_window_data *sprd_hwc_window = hwc_window;
+
+       RETURN_VAL_IF_FAIL(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(sprd_hwc_window->validated_type == TDM_COMPOSITION_VIDEO, TDM_ERROR_INVALID_PARAMETER);
+
+       *formats = hwc_window_video_formats;
+       *count = sizeof(hwc_window_video_formats) / sizeof(tbm_format);
+
+       return TDM_ERROR_NONE;
+}