Implemented capture features. Based on source code of exynos 94/101294/8
authorAndrii Sokolenko <a.sokolenko@samsung.com>
Wed, 30 Nov 2016 14:35:03 +0000 (16:35 +0200)
committerAndrii Sokolenko <a.sokolenko@samsung.com>
Thu, 8 Dec 2016 17:00:02 +0000 (19:00 +0200)
Change-Id: Ia315602bc8f8260809a9864e68c377c8373a13ff
Signed-off-by: Andrii Sokolenko <a.sokolenko@samsung.com>
src/Makefile.am
src/tdm_sprd.c
src/tdm_sprd.h
src/tdm_sprd_capture.c [new file with mode: 0644]
src/tdm_sprd_display.c
src/tdm_sprd_pp.c

index 00e199e..9d6d6cd 100644 (file)
@@ -11,4 +11,5 @@ libtdm_sprd_la_SOURCES = \
        tdm_sprd_format.c \
        tdm_sprd_display.c \
        tdm_sprd_pp.c \
+       tdm_sprd_capture.c \
        tdm_sprd.c
index 7d78117..75e9222 100755 (executable)
@@ -115,6 +115,7 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        tdm_func_output sprd_func_output;
        tdm_func_layer sprd_func_layer;
        tdm_func_pp sprd_func_pp;
+       tdm_func_capture sprd_func_capture;
        tdm_error ret;
 
        if (!dpy) {
@@ -149,6 +150,7 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        sprd_func_display.display_get_fd = sprd_display_get_fd;
        sprd_func_display.display_handle_events = sprd_display_handle_events;
        sprd_func_display.display_create_pp = sprd_display_create_pp;
+       sprd_func_display.display_get_capture_capability = sprd_capture_get_capability;
 
        memset(&sprd_func_output, 0, sizeof(sprd_func_output));
        sprd_func_output.output_get_capability = sprd_output_get_capability;
@@ -163,6 +165,7 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        sprd_func_output.output_get_dpms = sprd_output_get_dpms;
        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;
 
        memset(&sprd_func_layer, 0, sizeof(sprd_func_layer));
        sprd_func_layer.layer_get_capability = sprd_layer_get_capability;
@@ -181,6 +184,13 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        sprd_func_pp.pp_commit = sprd_pp_commit;
        sprd_func_pp.pp_set_done_handler = sprd_pp_set_done_handler;
 
+       memset(&sprd_func_capture, 0, sizeof(sprd_func_capture));
+       sprd_func_capture.capture_attach = sprd_capture_attach;
+       sprd_func_capture.capture_commit = sprd_capture_commit;
+       sprd_func_capture.capture_destroy = sprd_capture_destroy;
+       sprd_func_capture.capture_set_done_handler = sprd_capture_set_done_handler;
+       sprd_func_capture.capture_set_info = sprd_capture_set_info;
+
        ret = tdm_backend_register_func_display(dpy, &sprd_func_display);
        if (ret != TDM_ERROR_NONE)
                goto failed_l;
@@ -197,6 +207,10 @@ tdm_sprd_init(tdm_display *dpy, tdm_error *error)
        if (ret != TDM_ERROR_NONE)
                goto failed_l;
 
+       ret = tdm_backend_register_func_capture(dpy, &sprd_func_capture);
+       if (ret != TDM_ERROR_NONE)
+               goto failed_l;
+
        sprd_data->dpy = dpy;
        sprd_data->drm_fd = -1;
 
index 3b6042f..1903c92 100644 (file)
@@ -53,6 +53,20 @@ tdm_error    sprd_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
 tdm_error    sprd_pp_commit(tdm_pp *pp);
 tdm_error    sprd_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data);
 
+/* Capture funcs */
+tdm_error    sprd_capture_get_capability (tdm_backend_data *bdata, tdm_caps_capture *caps);
+tdm_capture* sprd_capture_create (tdm_output *output, tdm_error *error);
+void         sprd_capture_destroy(tdm_capture *capture);
+tdm_error    sprd_capture_attach(tdm_capture *capture, tbm_surface_h buffer);
+tdm_error    sprd_capture_set_info(tdm_capture *capture, tdm_info_capture *info);
+tdm_error    sprd_capture_commit(tdm_capture *capture);
+tdm_error    sprd_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data);
+
+tdm_error    sprd_output_attach_capture(tdm_output *output, tdm_capture *capture);
+void         sprd_output_dettach_capture(tdm_output *output, tdm_capture *capture);
+
+
+tdm_backend_data* sprd_output_get_sprd_data(tdm_output *output);
 
 /* sprd module internal macros, structures, functions */
 #define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **")
@@ -84,7 +98,7 @@ tdm_error    sprd_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void
                return val;\
        } \
 }
-
+#define LAYER_COUNT_PER_OUTPUT   2
 #define NOP
 
 #define RETURN_VOID_IF_FAIL(cond) RETURN_VAL_IF_FAIL(cond, NOP)
@@ -113,4 +127,6 @@ tdm_pp*      tdm_sprd_pp_create(tdm_sprd_data *sprd_data, tdm_error *error);
 void         tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p);
 tdm_error    tdm_sprd_display_init_event_handling(tdm_sprd_data *sprd_data);
 void         tdm_sprd_display_deinit_event_handling(tdm_sprd_data *sprd_data);
+tdm_error    sprd_layer_get_buffer(tdm_layer *layer, tbm_surface_h *surface);
+tdm_error    sprd_layer_get_zpos(tdm_layer *layer, int *zpos);
 #endif /* _TDM_SPRD_H_ */
diff --git a/src/tdm_sprd_capture.c b/src/tdm_sprd_capture.c
new file mode 100644 (file)
index 0000000..cea1137
--- /dev/null
@@ -0,0 +1,883 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_sprd.h"
+#include "tdm_helper.h"
+
+typedef struct _tdm_sprd_capture_buffer {
+       tbm_surface_h buffer;
+       struct list_head link;
+} tdm_sprd_capture_buffer;
+
+typedef struct _tdm_sprd_capture_pp_data {
+       tdm_pp * pp_link;
+       tbm_surface_h src_buffer;
+       tbm_surface_h dst_buffer;
+       struct list_head link;
+} tdm_sprd_capture_pp_data;
+
+typedef struct _tdm_sprd_capture_composite_data {
+       tbm_surface_h temp_layer_buffer[LAYER_COUNT_PER_OUTPUT];
+       tdm_pos dst_pos[LAYER_COUNT_PER_OUTPUT];
+       int zpos[LAYER_COUNT_PER_OUTPUT];
+       tbm_surface_h client_buffer;
+       tbm_surface_h temp_composite_buffer;
+       tdm_sprd_capture_pp_data * composite_buf_pp_task;
+       int current_done_buf_num;
+       int need_done_buf_num;
+       struct list_head link;
+} tdm_sprd_capture_composite;
+
+typedef struct _tdm_sprd_capture_data {
+       int stamp;
+       int removing;
+       tdm_sprd_data *sprd_data;
+
+       tdm_output *output_data;
+
+       tdm_info_capture info;
+       int info_changed;
+       struct list_head pending_buffer_list;
+       struct list_head pp_convert_list;
+       struct list_head composite_list;
+
+       struct {
+               tdm_event_loop_source *timer_source;
+       } stream;
+
+       tdm_capture_done_handler done_func;
+       void *done_user_data;
+       struct list_head link;
+} tdm_sprd_capture_data;
+
+static tbm_format capture_client_formats[] = {
+       TBM_FORMAT_XRGB8888,
+       TBM_FORMAT_ARGB8888,
+       TBM_FORMAT_NV12,
+       TBM_FORMAT_YUV420
+};
+
+#define NUM_CAPTURE_FORMAT   (sizeof(capture_client_formats) / sizeof(capture_client_formats[0]))
+
+static int capture_list_init;
+static struct list_head capture_list;
+static int capture_stamp = 1001;
+
+int _tdm_sprd_capture_check_struct(tdm_sprd_capture_data *capture_data)
+{
+       RETURN_VAL_IF_FAIL(capture_list_init == 1, 0);
+       if (capture_data == NULL) {
+               TDM_WRN("capture nil(0). Received NULL pointer");
+               return 0;
+       }
+       tdm_sprd_capture_data * capture_next = NULL;
+       LIST_FOR_EACH_ENTRY(capture_next, &capture_list, link) {
+               if (capture_next->stamp == capture_data->stamp)
+                       return 1;
+       }
+       TDM_INFO("capture %p(%d). Maybe, receive handler after remove",
+                       capture_data, capture_data->stamp);
+       return 0;
+}
+
+static void
+_tdm_sprd_capture_oneshot_center_rect(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *fit)
+{
+       float rw = (float)src_w / dst_w;
+       float rh = (float)src_h / dst_h;
+
+       fit->x = fit->y = 0;
+
+       if (rw > rh) {
+               fit->w = dst_w;
+               fit->h = src_h / rw;
+               fit->y = (dst_h - fit->h) / 2;
+       } else if (rw < rh) {
+               fit->w = src_w / rh;
+               fit->h = dst_h;
+               fit->x = (dst_w - fit->w) / 2;
+       } else {
+               fit->w = dst_w;
+               fit->h = dst_h;
+       }
+
+       fit->x = fit->x & ~0x1;
+}
+
+static void
+_tdm_sprd_capture_oneshot_rect_scale(int src_w, int src_h, int dst_w, int dst_h, tdm_pos *scale)
+{
+       float ratio;
+       tdm_pos center = {0,};
+
+       _tdm_sprd_capture_oneshot_center_rect(src_w, src_h, dst_w, dst_h, &center);
+
+       ratio = (float)center.w / src_w;
+       scale->x = scale->x * ratio + center.x;
+       scale->y = scale->y * ratio + center.y;
+       scale->w = scale->w * ratio;
+       scale->h = scale->h * ratio;
+}
+
+static void
+_tdm_sprd_capture_destroy_converter(tdm_sprd_capture_pp_data ** pp_task_p)
+{
+       RETURN_VOID_IF_FAIL(pp_task_p);
+       RETURN_VOID_IF_FAIL(*pp_task_p);
+       LIST_DEL(&(*pp_task_p)->link);
+       if ((*pp_task_p)->pp_link)
+               sprd_pp_destroy((*pp_task_p)->pp_link);
+       if ((*pp_task_p)->src_buffer) {
+               tdm_buffer_unref_backend((*pp_task_p)->src_buffer);
+               (*pp_task_p)->src_buffer = NULL;
+       }
+       if ((*pp_task_p)->dst_buffer) {
+               tdm_buffer_unref_backend((*pp_task_p)->dst_buffer);
+               (*pp_task_p)->dst_buffer = NULL;
+       }
+       free(*pp_task_p);
+       *pp_task_p = NULL;
+}
+
+static tdm_error
+_tdm_sprd_capture_composite_sw(tdm_sprd_capture_data *capture_data,
+                                                          tdm_sprd_capture_composite * composite_data,
+                                                          tbm_surface_h composite_buf)
+{
+       int i,k,swapped = 0;
+       tdm_error tdm_err = TDM_ERROR_NONE;
+       tbm_surface_h temp_buffer = NULL;
+       int temp_zpos = 0;
+       tdm_pos temp_dpos = {0,0,0,0};
+/* Good old bubble sort */
+       for (k = 0; k < LAYER_COUNT_PER_OUTPUT-1; ++k) {
+               swapped = 0;
+               for (i = 0; i < LAYER_COUNT_PER_OUTPUT - 1 - k; ++i) {
+                       if (composite_data->zpos[i] > composite_data->zpos[i+1]) {
+                               temp_buffer = composite_data->temp_layer_buffer[i];
+                               temp_zpos = composite_data->zpos[i];
+                               temp_dpos = composite_data->dst_pos[i];
+                               composite_data->temp_layer_buffer[i] = composite_data->temp_layer_buffer[i+1];
+                               composite_data->zpos[i] = composite_data->zpos[i+1];
+                               composite_data->dst_pos[i] = composite_data->dst_pos[i+1];
+                               composite_data->dst_pos[i+1] = temp_dpos;
+                               composite_data->temp_layer_buffer[i+1] = temp_buffer;
+                               composite_data->zpos[i+1] = temp_zpos;
+                       }
+               }
+               if (!swapped)
+                       break;
+       }
+       for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++){
+               if (composite_data->temp_layer_buffer[i]) {
+                       tdm_err = tdm_helper_convert_buffer(composite_data->temp_layer_buffer[i],
+                                                                                                 composite_buf,
+                                                                                                 &composite_data->dst_pos[i],
+                                                                                                 &composite_data->dst_pos[i], 0 , 1);
+                       if (tdm_err != TDM_ERROR_NONE) {
+                               TDM_WRN("Capture %p error %d Can't composite buffers src %p dst %p. Skip",
+                                               capture_data,  tdm_err, composite_data->temp_layer_buffer[i], composite_buf);
+                       }
+                       tdm_buffer_unref_backend(composite_data->temp_layer_buffer[i]);
+                       composite_data->temp_layer_buffer[i] = NULL;
+               }
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_sprd_capture_pp_done_handler (tdm_pp *pp, tbm_surface_h src,
+                                                         tbm_surface_h dst, void *user_data)
+{
+       if(!_tdm_sprd_capture_check_struct(user_data)){
+               return;
+       }
+       tdm_sprd_capture_data *capture_data = user_data;
+       if (capture_data->removing) {
+               TDM_INFO("Capture removing. Skip handler");
+               return;
+       }
+       tdm_sprd_capture_composite *composite_data = NULL, *composite_next = NULL;
+       tdm_sprd_capture_pp_data  *pp_task = NULL, *pp_tasks_next = NULL;
+       int i;
+       LIST_FOR_EACH_ENTRY_SAFE(pp_task, pp_tasks_next, &capture_data->pp_convert_list, link) {
+               if (pp_task->pp_link == pp) {
+                       tdm_buffer_unref_backend(pp_task->src_buffer);
+                       pp_task->src_buffer = NULL;
+                       tdm_buffer_unref_backend(pp_task->dst_buffer);
+                       pp_task->dst_buffer = NULL;
+                       break;
+               }
+       }
+       LIST_FOR_EACH_ENTRY_SAFE (composite_data, composite_next, &capture_data->composite_list, link) {
+               if (composite_data->client_buffer && composite_data->client_buffer == dst) {
+                       LIST_DEL(&composite_data->link);
+                       tdm_buffer_unref_backend(composite_data->client_buffer);
+                       tdm_buffer_unref_backend(composite_data->temp_composite_buffer);
+                       composite_data->temp_composite_buffer = NULL;
+                       if (capture_data->done_func) {
+                               capture_data->done_func(capture_data,
+                                                                       composite_data->client_buffer,
+                                                                       capture_data->done_user_data);
+                       }
+                       free(composite_data);
+                       break;
+               }
+               for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++) {
+                       if (composite_data->temp_layer_buffer[i] && composite_data->temp_layer_buffer[i] == dst) {
+                               composite_data->current_done_buf_num++;
+                       }
+               }
+               if (composite_data->current_done_buf_num == composite_data->need_done_buf_num) {
+                       if (!composite_data->temp_composite_buffer) {
+                               _tdm_sprd_capture_composite_sw(capture_data, composite_data,
+                                                                                          composite_data->client_buffer);
+                               tdm_buffer_unref_backend(composite_data->client_buffer);
+                               if (capture_data->done_func) {
+                                       capture_data->done_func(capture_data,
+                                                                               composite_data->client_buffer,
+                                                                               capture_data->done_user_data);
+                               }
+                               LIST_DEL(&composite_data->link);
+                               free(composite_data);
+                       }
+                       else {
+                               _tdm_sprd_capture_composite_sw(capture_data, composite_data,
+                                                                                          composite_data->temp_composite_buffer);
+                               sprd_pp_commit(composite_data->composite_buf_pp_task->pp_link);
+                       }
+                       composite_data->current_done_buf_num = 0;
+                       break;
+               }
+       }
+       TDM_DBG("capture pp handler done");
+}
+
+static tdm_error
+_tdm_sprd_capture_make_converter(tdm_sprd_capture_data *capture_data,
+                                                                tbm_surface_h src, tbm_surface_h dst,
+                                                                tdm_pos *src_pos, tdm_pos *dst_pos,
+                                                                tdm_sprd_capture_pp_data ** pp_task_p)
+{
+       tdm_error tdm_err = TDM_ERROR_NONE;
+       tdm_pp *pp = NULL;
+       tdm_info_pp info_pp;
+       tdm_sprd_capture_pp_data  *new_pp_task = NULL, *pp_task = NULL, *pp_tasks_next = NULL;
+       if (pp_task_p == NULL) {
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(pp_task, pp_tasks_next, &capture_data->pp_convert_list, link) {
+               if (pp_task->src_buffer == NULL &&
+                       pp_task->dst_buffer == NULL) {
+                       new_pp_task = pp_task;
+                       new_pp_task->dst_buffer = tdm_buffer_ref_backend(dst);
+                       new_pp_task->src_buffer = tdm_buffer_ref_backend(src);
+                       break;
+               }
+       }
+       if (new_pp_task == NULL) {
+               new_pp_task = calloc (1, sizeof(tdm_sprd_capture_pp_data));
+               if (new_pp_task == NULL) {
+                       TDM_WRN("Out of memory");
+                       return TDM_ERROR_OUT_OF_MEMORY;
+               }
+               new_pp_task->dst_buffer = tdm_buffer_ref_backend(dst);
+               new_pp_task->src_buffer = tdm_buffer_ref_backend(src);
+               LIST_ADD(&new_pp_task->link, &capture_data->pp_convert_list);
+               pp = tdm_sprd_pp_create(capture_data->sprd_data, &tdm_err);
+               if (tdm_err != TDM_ERROR_NONE) {
+                       TDM_WRN("can't create pp");
+                       goto fail;
+               }
+               if((tdm_err = sprd_pp_set_done_handler(pp, _tdm_sprd_capture_pp_done_handler,
+                                                                                                 capture_data)) != TDM_ERROR_NONE) {
+                       TDM_WRN("can't create done handler");
+                       goto fail;
+               }
+               new_pp_task->pp_link = pp;
+       }
+       CLEAR(info_pp);
+       tbm_format src_format = tbm_surface_get_format(src);
+       unsigned int src_bpp = tbm_surface_internal_get_bpp(src_format);
+       unsigned int src_stride = 0;
+       if (!tbm_surface_internal_get_plane_data(src, 0, NULL, NULL, &src_stride)) {
+               TDM_WRN("can't get stride");
+               tdm_err = TDM_ERROR_OPERATION_FAILED;
+               goto fail;
+       }
+       if (IS_RGB(src_format)) {
+               src_bpp >>= 3;
+               if (src_bpp != 0)
+                       src_stride /= src_bpp;
+       }
+       info_pp.src_config.format = tbm_surface_get_format(src);
+       info_pp.src_config.pos.x = (src_pos) ? src_pos->x : 0;
+       info_pp.src_config.pos.y = (src_pos) ? src_pos->y : 0;
+       info_pp.src_config.pos.w = (src_pos) ? src_pos->w : tbm_surface_get_width(src);
+       info_pp.src_config.pos.h = (src_pos) ? src_pos->h : tbm_surface_get_height(src);
+       info_pp.src_config.size.h = src_stride;
+       info_pp.src_config.size.v = tbm_surface_get_height(src);
+
+       tbm_format dst_format = tbm_surface_get_format(dst);
+       unsigned int dst_bpp = tbm_surface_internal_get_bpp(dst_format);
+       unsigned int dst_stride = 0;
+       if (!tbm_surface_internal_get_plane_data(dst, 0, NULL, NULL, &dst_stride)) {
+               TDM_WRN("can't get stride");
+               tdm_err = TDM_ERROR_OPERATION_FAILED;
+               goto fail;
+       }
+       if (IS_RGB(dst_format)) {
+               dst_bpp >>= 3;
+               if (dst_bpp != 0)
+                       dst_stride /= dst_bpp;
+       }
+
+       info_pp.dst_config.format = dst_format;
+       info_pp.dst_config.pos.x = (dst_pos) ? dst_pos->x : 0;
+       info_pp.dst_config.pos.y = (dst_pos) ? dst_pos->y : 0;
+       info_pp.dst_config.pos.w = (dst_pos) ? dst_pos->w : tbm_surface_get_width(dst);
+       info_pp.dst_config.pos.h = (dst_pos) ? dst_pos->h : tbm_surface_get_height(dst);
+       info_pp.dst_config.size.h = dst_stride;
+       info_pp.dst_config.size.v = tbm_surface_get_height(dst);
+
+       if((tdm_err = sprd_pp_set_info(new_pp_task->pp_link, &info_pp)) != TDM_ERROR_NONE) {
+               TDM_WRN("can't set pp info");
+               tdm_err = TDM_ERROR_OPERATION_FAILED;
+               goto fail;
+       }
+       if ((tdm_err = sprd_pp_attach(new_pp_task->pp_link, src, dst)) != TDM_ERROR_NONE) {
+               TDM_WRN("can't set buffers to pp");
+               tdm_err = TDM_ERROR_OPERATION_FAILED;
+               goto fail;
+       }
+       *pp_task_p = new_pp_task;
+       return TDM_ERROR_NONE;
+
+fail:
+       if (pp)
+               sprd_pp_destroy(pp);
+       if (new_pp_task) {
+               LIST_DEL(&new_pp_task->link);
+               if (new_pp_task->dst_buffer)
+                       tdm_buffer_unref_backend(dst);
+               if (new_pp_task->src_buffer)
+                       tdm_buffer_unref_backend(src);
+               free(new_pp_task);
+       }
+       return tdm_err;
+}
+
+static tdm_error
+_tdm_sprd_capture_oneshot_composite_layers_sw(tdm_sprd_capture_data *capture_data,
+                                                                                         tbm_surface_h buffer)
+{
+       tbm_surface_info_s buf_info;
+       const tdm_output_mode *current_mode = NULL;
+       tbm_surface_h surface = NULL;
+       tdm_layer **tdm_layer_array = NULL;
+       tdm_sprd_capture_composite *composite_data = NULL;
+       tdm_sprd_capture_pp_data ** pp_tasks = NULL;
+       int layer_count = 0;
+       int int_err, i;
+       tdm_error tdm_err = TDM_ERROR_NONE;
+       if ((sprd_output_get_mode(capture_data->output_data, &current_mode)) != TDM_ERROR_NONE) {
+               TDM_ERR("can't get output mode");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+       if (current_mode == NULL) {
+               TDM_WRN("Output mode not init. Can't capture");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       int_err = tbm_surface_get_info(buffer, &buf_info);
+       RETURN_VAL_IF_FAIL(int_err == TBM_SURFACE_ERROR_NONE, TDM_ERROR_BAD_REQUEST);
+       tdm_layer_array = sprd_output_get_layers(capture_data->output_data, &layer_count, &tdm_err);
+       if (tdm_err != TDM_ERROR_NONE) {
+               TDM_WRN("can't get layers list");
+               goto fail;
+       }
+       if (layer_count == 0) {
+               TDM_WRN("layer list is empty nothing to capture");
+               goto fail;
+       }
+       composite_data = calloc(1, sizeof(tdm_sprd_capture_composite));
+       if (composite_data == NULL) {
+               TDM_WRN("Out of memory");
+               tdm_err = TDM_ERROR_OUT_OF_MEMORY;
+               goto fail;
+       }
+
+       composite_data->client_buffer = tdm_buffer_ref_backend(buffer);
+       LIST_ADD(&composite_data->link, &capture_data->composite_list);
+       pp_tasks = calloc(layer_count, sizeof(tdm_sprd_capture_pp_data *));
+       if (pp_tasks == NULL) {
+               TDM_WRN("Out of memory");
+               tdm_err = TDM_ERROR_OUT_OF_MEMORY;
+               goto fail;
+       }
+       for (i = 0; i < layer_count; ++i) {
+               tdm_info_layer layer_info;
+               CLEAR(layer_info);
+               if (sprd_layer_get_info(tdm_layer_array[i], &layer_info) != TDM_ERROR_NONE) {
+                       TDM_WRN("can't get layer %p info. Skip", tdm_layer_array[i]);
+                       continue;
+               }
+               if (layer_info.src_config.pos.h == 0 || layer_info.src_config.pos.w == 0) {
+                       TDM_INFO("layer %p info is NULL. Skip", tdm_layer_array[i]);
+               }
+               if (sprd_layer_get_buffer(tdm_layer_array[i], &surface) != TDM_ERROR_NONE) {
+                       TDM_WRN("can't get layer %p surface. Skip", tdm_layer_array[i]);
+                       continue;
+               }
+               if (surface == NULL) {
+                       TDM_INFO("layer %p buffer is NULL. Skip", tdm_layer_array[i]);
+                       continue;
+               }
+               tdm_buffer_ref_backend(surface);
+               TDM_DBG("Get layer %p surface %p", tdm_layer_array[i], surface);
+               if (1) {
+                       tbm_surface_h temp_buffer = tbm_surface_create(tbm_surface_get_width(buffer),
+                                                                                                                  tbm_surface_get_height(buffer),
+                                                                                                                  TBM_FORMAT_ARGB8888);
+                       if (temp_buffer == NULL) {
+                               TDM_WRN("Out of memory");
+                               tdm_buffer_unref_backend(surface);
+                               continue;
+                       }
+                       tdm_pos src_pos = {.x = 0, .y = 0,
+                                                          .w = tbm_surface_get_width(surface),
+                                                          .h = tbm_surface_get_height(surface)};
+                       int output_width = current_mode->hdisplay;
+                       int width = layer_info.src_config.pos.w;
+                       int pos_x = layer_info.dst_pos.x;
+                       tdm_pos dst_pos = {.x = pos_x, .y = layer_info.dst_pos.y,
+                                                          .w = ((width + pos_x) <= output_width ? width : output_width - pos_x),
+                                                          .h = layer_info.src_config.pos.h };
+                       _tdm_sprd_capture_oneshot_rect_scale(current_mode->hdisplay, current_mode->vdisplay,
+                                                                                                tbm_surface_get_width(buffer),
+                                                                                                tbm_surface_get_height(buffer),
+                                                                                                &dst_pos);
+                       tdm_err = _tdm_sprd_capture_make_converter(capture_data, surface, temp_buffer,
+                                                                                                          &src_pos, &dst_pos, &pp_tasks[i]);
+                       if (tdm_err != TDM_ERROR_NONE) {
+                               TDM_WRN("can't create converter");
+                               tdm_buffer_unref_backend(surface);
+                               tdm_buffer_unref_backend(temp_buffer);
+                               continue;
+                       }
+
+                       int zpos;
+                       if (sprd_layer_get_zpos(tdm_layer_array[i], &zpos) != TDM_ERROR_NONE) {
+                               TDM_WRN("can't get layer %p zpos", tdm_layer_array[i]);
+                               _tdm_sprd_capture_destroy_converter(&pp_tasks[i]);
+                               tdm_buffer_unref_backend(surface);
+                               tdm_buffer_unref_backend(temp_buffer);
+                               continue;
+                       }
+                       composite_data->temp_layer_buffer[i] = temp_buffer;
+                       composite_data->dst_pos[i] = dst_pos;
+                       composite_data->zpos[i] = zpos;
+                       composite_data->need_done_buf_num++;
+               }
+               tdm_buffer_unref_backend(surface);
+       }
+
+       if (!composite_data->need_done_buf_num) {
+               TDM_INFO("Layers buffer are empty. Nothing to do");
+               tdm_err = TDM_ERROR_NONE;
+               goto fail;
+       }
+
+       if (!IS_RGB(tbm_surface_get_format(composite_data->client_buffer))) {
+               tdm_sprd_capture_pp_data * pp_task = NULL;
+               composite_data->temp_composite_buffer = tbm_surface_create(tbm_surface_get_width(buffer),
+                                                                                                          tbm_surface_get_height(buffer),
+                                                                                                          TBM_FORMAT_ARGB8888);
+               if (composite_data->temp_composite_buffer == NULL) {
+                       TDM_WRN("Out of memory");
+                       tdm_err = TDM_ERROR_OUT_OF_MEMORY;
+                       goto fail;
+               }
+               tdm_err = _tdm_sprd_capture_make_converter(capture_data, composite_data->temp_composite_buffer,
+                                                                                                  composite_data->client_buffer,
+                                                                                                  NULL, NULL, &pp_task);
+               if (tdm_err != TDM_ERROR_NONE) {
+                       TDM_WRN("can't create converter");
+                       goto fail;
+               }
+               composite_data->composite_buf_pp_task = pp_task;
+       }
+       for (i = 0; i < layer_count; i++) {
+               if (pp_tasks[i]) {
+                       tdm_err = sprd_pp_commit(pp_tasks[i]->pp_link);
+                       if (tdm_err != TDM_ERROR_NONE) {
+                               composite_data->need_done_buf_num--;
+                               _tdm_sprd_capture_destroy_converter(&pp_tasks[i]);
+                               tdm_buffer_unref_backend(composite_data->temp_layer_buffer[i]);
+                               composite_data->temp_layer_buffer[i] = NULL;
+                       }
+               }
+       }
+       if (!composite_data->need_done_buf_num) {
+               TDM_WRN("Can't capture layers");
+               goto fail;
+       }
+       if (tdm_layer_array) {
+               free(tdm_layer_array);
+       }
+       if (pp_tasks) {
+               free(pp_tasks);
+       }
+       return TDM_ERROR_NONE;
+fail:
+       if (pp_tasks) {
+               for (i = 0; i < layer_count; ++i) {
+                       if (pp_tasks[i])
+                               _tdm_sprd_capture_destroy_converter(&pp_tasks[i]);
+               }
+               free(pp_tasks);
+       }
+       if (composite_data) {
+               LIST_DEL(&composite_data->link);
+               if (composite_data->composite_buf_pp_task) {
+                       _tdm_sprd_capture_destroy_converter(&composite_data->composite_buf_pp_task);
+               }
+               if (composite_data->temp_composite_buffer != NULL) {
+                       tdm_buffer_unref_backend(composite_data->temp_composite_buffer);
+               }
+               for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++) {
+                       if (composite_data->temp_layer_buffer[i] != NULL) {
+                               tdm_buffer_unref_backend(composite_data->temp_layer_buffer[i]);
+                       }
+               }
+               if (composite_data->client_buffer != NULL) {
+                       tdm_buffer_unref_backend(composite_data->client_buffer);
+                       if (capture_data->done_func) {
+                               capture_data->done_func(capture_data,
+                                                                               composite_data->client_buffer,
+                                                                               capture_data->done_user_data);
+                       }
+                       composite_data->client_buffer = NULL;
+               }
+               free(composite_data);
+       }
+       if (tdm_layer_array) {
+               free(tdm_layer_array);
+       }
+       return tdm_err;
+}
+
+void
+sprd_capture_destroy(tdm_capture *capture)
+{
+       tdm_sprd_capture_data *capture_data = capture;
+       if(!_tdm_sprd_capture_check_struct(capture_data)) {
+               return;
+       }
+       tdm_sprd_capture_buffer *b = NULL, *bb = NULL;
+       tdm_sprd_capture_pp_data  *pp_task = NULL, *pp_tasks_next = NULL;
+       tdm_sprd_capture_composite *composite = NULL, *composite_next = NULL;
+       int i;
+       capture_data->removing = 1;
+       TDM_DBG("capture(%p) destroy", capture_data);
+
+       LIST_FOR_EACH_ENTRY_SAFE(pp_task, pp_tasks_next, &capture_data->pp_convert_list, link) {
+               _tdm_sprd_capture_destroy_converter(&pp_task);
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE (composite, composite_next, &capture_data->composite_list, link) {
+               LIST_DEL(&composite->link);
+               for (i = 0; i < LAYER_COUNT_PER_OUTPUT; i++){
+                       if (composite->temp_layer_buffer[i]) {
+                               tdm_buffer_unref_backend(composite->temp_layer_buffer[i]);
+                               composite->temp_layer_buffer[i] = NULL;
+                       }
+               }
+               if (composite->client_buffer) {
+                       tdm_buffer_unref_backend(composite->client_buffer);
+                       if (capture_data->done_func) {
+                               capture_data->done_func(capture_data,
+                                                                               composite->client_buffer,
+                                                                               capture_data->done_user_data);
+                       }
+                       composite->client_buffer = NULL;
+               }
+               if (composite->temp_composite_buffer) {
+                       tdm_buffer_unref_backend(composite->temp_composite_buffer);
+                       composite->temp_composite_buffer = NULL;
+               }
+               free(composite);
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               if (capture_data->done_func) {
+                       capture_data->done_func(capture_data,
+                                                                       b->buffer,
+                                                                       capture_data->done_user_data);
+               }
+               free(b);
+       }
+       if (capture_data->stream.timer_source) {
+               TDM_DBG("capture %p removing postponed", capture_data);
+               return;
+       }
+       LIST_DEL(&capture_data->link);
+       capture_data->stamp = 0;
+       sprd_output_dettach_capture (capture_data->output_data, capture_data);
+       free(capture_data);
+}
+
+static tdm_error
+_tdm_sprd_capture_stream_timer_handler(void *user_data)
+{
+       tdm_sprd_capture_data *capture_data = user_data;
+       if(!_tdm_sprd_capture_check_struct(user_data)) {
+               return TDM_ERROR_NONE;
+       }
+
+       if (capture_data->removing) {
+               TDM_DBG("Capture %p Postponded removing", capture_data);
+               tdm_event_loop_source_remove(capture_data->stream.timer_source);
+               LIST_DEL(&capture_data->link);
+               capture_data->stamp = 0;
+               sprd_output_dettach_capture (capture_data->output_data, capture_data);
+               free(capture_data);
+               return TDM_ERROR_NONE;
+       }
+       unsigned int ms = 1000 / capture_data->info.frequency;
+       tdm_sprd_capture_buffer *b = NULL, *bb = NULL;
+       tbm_surface_h current_buffer = NULL;
+       tdm_error tdm_err = TDM_ERROR_NONE;
+       if (!capture_data->stream.timer_source) {
+               TDM_ERR("Timer removed");
+               return TDM_ERROR_NONE;
+       }
+       tdm_event_loop_source_timer_update(capture_data->stream.timer_source, ms);
+       if (!LIST_IS_EMPTY(&capture_data->composite_list)) {
+               TDM_DBG("Converter is busy");
+               return TDM_ERROR_NONE;
+       }
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               current_buffer = tdm_buffer_ref_backend(b->buffer);
+               free(b);
+               tdm_err = _tdm_sprd_capture_oneshot_composite_layers_sw(capture_data, current_buffer);
+               tdm_buffer_unref_backend(current_buffer);
+               break;
+       }
+       return tdm_err;
+}
+
+
+static tdm_error
+_tdm_sprd_capture_commit_stream(tdm_sprd_capture_data *capture_data)
+{
+       unsigned int ms = 1000 / capture_data->info.frequency;
+
+       if (!capture_data->stream.timer_source) {
+               capture_data->stream.timer_source =
+                       tdm_event_loop_add_timer_handler(capture_data->sprd_data->dpy,
+                                                                                        _tdm_sprd_capture_stream_timer_handler,
+                                                                                        capture_data, NULL);
+                       RETURN_VAL_IF_FAIL(capture_data->stream.timer_source != NULL, TDM_ERROR_OUT_OF_MEMORY);
+       }
+
+       tdm_event_loop_source_timer_update(capture_data->stream.timer_source, ms);
+
+       return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_sprd_capture_commit_oneshot(tdm_sprd_capture_data *capture_data)
+{
+       tdm_sprd_capture_buffer *b = NULL, *bb = NULL;
+       tbm_surface_h current_buffer = NULL;
+       tdm_error tdm_err = TDM_ERROR_NONE;
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &capture_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               current_buffer = tdm_buffer_ref_backend(b->buffer);
+               free(b);
+               tdm_err = _tdm_sprd_capture_oneshot_composite_layers_sw(capture_data, current_buffer);
+               tdm_buffer_unref_backend(current_buffer);
+               if (tdm_err != TDM_ERROR_NONE) {
+                       TDM_ERR("capture %p composite func return err %d", tdm_err);
+                       break;
+               }
+       }
+       return tdm_err;
+}
+
+tdm_error
+sprd_capture_get_capability(tdm_backend_data *bdata, tdm_caps_capture *caps)
+{
+       int i;
+
+       if (!caps || !bdata) {
+               TDM_ERR("invalid params");
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+
+       caps->capabilities = TDM_CAPTURE_CAPABILITY_OUTPUT|
+                                                TDM_CAPTURE_CAPABILITY_ONESHOT|
+                                                TDM_CAPTURE_CAPABILITY_STREAM;
+
+       caps->format_count = NUM_CAPTURE_FORMAT;
+       caps->formats = NULL;
+       if (NUM_CAPTURE_FORMAT) {
+               /* will be freed in frontend */
+               caps->formats = calloc(1, sizeof capture_client_formats);
+               if (!caps->formats) {
+                       TDM_ERR("alloc failed");
+                       return TDM_ERROR_OUT_OF_MEMORY;
+               }
+               for (i = 0; i < caps->format_count; i++)
+                       caps->formats[i] = capture_client_formats[i];
+       }
+
+       caps->min_w = 16;
+       caps->min_h = 8;
+       caps->preferred_align = 2;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_capture*
+sprd_capture_create(tdm_output *output, tdm_error *error)
+{
+       if (!output) {
+               TDM_ERR("invalid params");
+               if (error) {
+                       *error = TDM_ERROR_INVALID_PARAMETER;
+               }
+               return NULL;
+       }
+       tdm_sprd_capture_data *capture_data = calloc(1, sizeof(tdm_sprd_capture_data));
+       if (!capture_data) {
+               TDM_ERR("alloc failed");
+               if (error)
+                       *error = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
+       if ((capture_data->sprd_data = sprd_output_get_sprd_data(output)) == NULL) {
+               TDM_ERR("invalid params");
+               if (error)
+                       *error = TDM_ERROR_INVALID_PARAMETER;
+               goto fail;
+       }
+
+       if ((sprd_output_attach_capture(output, capture_data)) != TDM_ERROR_NONE) {
+               TDM_ERR("can't attach capture to output");
+               if (error)
+                       *error = TDM_ERROR_OPERATION_FAILED;
+               goto fail;
+       }
+       capture_data->output_data = output;
+       capture_data->stamp = capture_stamp++;
+       LIST_INITHEAD(&capture_data->pending_buffer_list);
+       LIST_INITHEAD(&capture_data->pp_convert_list);
+       LIST_INITHEAD(&capture_data->composite_list);
+
+       if (!capture_list_init) {
+               capture_list_init = 1;
+               LIST_INITHEAD(&capture_list);
+       }
+       LIST_ADDTAIL(&capture_data->link, &capture_list);
+       TDM_DBG("capture(%p) create", capture_data);
+       if (error) {
+               *error = TDM_ERROR_NONE;
+       }
+       return capture_data;
+fail:
+       if (capture_data)
+               free(capture_data);
+       return NULL;
+}
+
+tdm_error
+sprd_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
+{
+       tdm_sprd_capture_data *capture_data = capture;
+       if(!_tdm_sprd_capture_check_struct(capture_data)) {
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+       if (capture_data->removing) {
+               TDM_INFO("Capture removing. Skip call func");
+               return TDM_ERROR_BUSY;
+       }
+       RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+       capture_data->info = *info;
+       capture_data->info_changed = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
+{
+       tdm_sprd_capture_data *capture_data = capture;
+       tdm_sprd_capture_buffer *b;
+       if(!_tdm_sprd_capture_check_struct(capture_data)) {
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+       if (capture_data->removing) {
+               TDM_INFO("Capture removing. Skip call func");
+               return TDM_ERROR_BUSY;
+       }
+       RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
+       b = calloc(1, sizeof(tdm_sprd_capture_buffer));
+       if (!b) {
+               TDM_ERR("alloc failed");
+               return TDM_ERROR_NONE;
+       }
+       TDM_DBG("capture %p attach buffer %p", capture, buffer);
+       LIST_ADDTAIL(&b->link, &capture_data->pending_buffer_list);
+
+       b->buffer = buffer;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_capture_commit(tdm_capture *capture)
+{
+       tdm_sprd_capture_data *capture_data = capture;
+       tdm_error ret;
+       if(!_tdm_sprd_capture_check_struct(capture_data)) {
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+       if (capture_data->removing) {
+               TDM_INFO("Capture removing. Skip call func");
+               return TDM_ERROR_BUSY;
+       }
+       TDM_DBG("capture %p commit", capture);
+       if (capture_data->info.type == TDM_CAPTURE_TYPE_ONESHOT)
+               ret = _tdm_sprd_capture_commit_oneshot(capture_data);
+       else
+               ret = _tdm_sprd_capture_commit_stream(capture_data);
+
+       return ret;
+}
+
+tdm_error
+sprd_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
+{
+       tdm_sprd_capture_data *capture_data = capture;
+
+       if(!_tdm_sprd_capture_check_struct(capture_data)) {
+               return TDM_ERROR_INVALID_PARAMETER;
+       }
+       if (capture_data->removing) {
+               TDM_INFO("Capture removing. Skip call func");
+               return TDM_ERROR_BUSY;
+       }
+       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+       capture_data->done_func = func;
+       capture_data->done_user_data = user_data;
+       TDM_DBG("capture %p set done handler func %p", capture, func);
+       return TDM_ERROR_NONE;
+}
index d7f1f88..7dd95f6 100644 (file)
@@ -9,7 +9,6 @@
 #include "tdm_sprd.h"
 
 #define MIN_WIDTH   32
-#define LAYER_COUNT_PER_OUTPUT   2
 #ifdef HAVE_FB_VBLANK
 /** @TODO fb event struct */
 #else
@@ -49,6 +48,11 @@ typedef struct _tdm_sprd_display_buffer {
        unsigned int count;
 } tdm_sprd_display_buffer;
 
+typedef struct _tdm_sprd_output_capture_data {
+       tdm_capture * tdm_capture_p;
+       struct list_head link;
+} tdm_sprd_output_capture_data;
+
 struct _tdm_sprd_output_data {
        struct list_head link;
 
@@ -77,6 +81,7 @@ struct _tdm_sprd_output_data {
 
        tdm_output_dpms dpms_value;
 
+       struct list_head capture_list;
 };
 
 struct _tdm_sprd_layer_data {
@@ -783,7 +788,7 @@ _tdm_sprd_display_create_output_LCD(tdm_sprd_data *sprd_data)
                free(output_data);
                return NULL;
        }
-
+       LIST_INITHEAD (&output_data->capture_list);
        return output_data;
 }
 
@@ -797,6 +802,12 @@ tdm_sprd_display_destroy_output_list(tdm_sprd_data *sprd_data)
 
        LIST_FOR_EACH_ENTRY_SAFE(o, oo, &sprd_data->output_list, link) {
                LIST_DEL(&o->link);
+               if (!LIST_IS_EMPTY(&o->capture_list)) {
+                       tdm_sprd_output_capture_data *l = NULL, *ll = NULL;
+                       LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->capture_list, link) {
+                               sprd_capture_destroy(l->tdm_capture_p);
+                       }
+               }
                if (!LIST_IS_EMPTY(&o->layer_list)) {
                        tdm_sprd_layer_data *l = NULL, *ll = NULL;
                        LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
@@ -975,7 +986,7 @@ sprd_output_get_layers(tdm_output *output, int *count, tdm_error *error)
        tdm_sprd_output_data *output_data = output;
        tdm_sprd_layer_data *layer_data = NULL;
        tdm_layer **layers;
-       tdm_error ret;
+       tdm_error ret = TDM_ERROR_OPERATION_FAILED;
        int i;
 
        RETURN_VAL_IF_FAIL(output_data, NULL);
@@ -1368,7 +1379,6 @@ _sprd_drm_user_handler(struct drm_event *event)
 
        if (event->type != DRM_SPRD_IPP_EVENT)
                return -1;
-
        tdm_sprd_pp_handler((struct drm_sprd_ipp_event *) event);
 
        return 0;
@@ -1434,3 +1444,69 @@ tdm_sprd_display_deinit_event_handling(tdm_sprd_data *sprd_data)
 
        drmRemoveUserHandler(sprd_data->drm_fd, _sprd_drm_user_handler);
 }
+
+tdm_backend_data*
+sprd_output_get_sprd_data(tdm_output *output)
+{
+       RETURN_VAL_IF_FAIL(output, NULL);
+       tdm_sprd_output_data *output_data = output;
+       return output_data->sprd_data;
+}
+
+tdm_error
+sprd_output_attach_capture(tdm_output *output, tdm_capture *capture)
+{
+       RETURN_VAL_IF_FAIL(output, 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);
+       tdm_sprd_output_data *output_data = output;
+       output_capture_data_p->tdm_capture_p = capture;
+       LIST_ADD(&output_capture_data_p->link, &output_data->capture_list);
+       TDM_DBG("capture attached");
+       return TDM_ERROR_NONE;
+}
+
+void
+sprd_output_dettach_capture(tdm_output *output, tdm_capture *capture)
+{
+       RETURN_VOID_IF_FAIL(output);
+       tdm_sprd_output_data *output_data = output;
+       if (!LIST_IS_EMPTY(&output_data->capture_list)) {
+               tdm_sprd_output_capture_data *l = NULL, *ll = NULL;
+               LIST_FOR_EACH_ENTRY_SAFE(l, ll, &output_data->capture_list, link) {
+                       if (l->tdm_capture_p == capture) {
+                               LIST_DEL(&l->link);
+                               free(l);
+                       }
+               }
+       }
+}
+
+tdm_error
+sprd_layer_get_buffer(tdm_layer *layer, tbm_surface_h *surface)
+{
+       tdm_sprd_layer_data *layer_data = layer;
+       RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+       if (!layer_data->display_buffer) {
+               if (surface) {
+                       *surface = NULL;
+               }
+               return TDM_ERROR_NONE;
+       }
+       if (surface) {
+               *surface = layer_data->display_buffer->buffer;
+       }
+       return  TDM_ERROR_NONE;
+}
+
+tdm_error
+sprd_layer_get_zpos(tdm_layer *layer, int *zpos)
+{
+       tdm_sprd_layer_data *layer_data = layer;
+       RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+       if (zpos) {
+               *zpos = layer_data->zpos;
+       }
+       return TDM_ERROR_NONE;
+}
index 4902b66..c527354 100644 (file)
@@ -114,7 +114,7 @@ int _tdm_sprd_pp_check_struct(tdm_sprd_pp_data *pp_data)
                if (pp_next->stamp == pp_data->stamp)
                        return 1;
        }
-       TDM_ERR("pp %p(%d). Wrong ", pp_data, pp_data->stamp);
+       TDM_INFO("pp %p(%d). Maybe, receive handler after remove", pp_data, pp_data->stamp);
        return 0;
 }
 
@@ -211,7 +211,7 @@ _tdm_sprd_pp_property_format_check(struct drm_sprd_ipp_property *prop)
                TDM_DBG("dst format change fmt(%c%c%c%c) -> fmt(%c%c%c%c)",
                                FOURCC_STR(dst_fmt), FOURCC_STR(change_fmt));
 }
-
+#endif
 static unsigned int
 _tdm_sprd_pp_set(tdm_sprd_pp_data *pp_data, tdm_info_pp *info,
                                 unsigned int prop_id)
@@ -261,7 +261,6 @@ _tdm_sprd_pp_set(tdm_sprd_pp_data *pp_data, tdm_info_pp *info,
        TDM_DBG("pp %p(%d). success. prop_id(%u) ", pp_data, pp_data->stamp, property.prop_id);
        return property.prop_id;
 }
-#endif
 #if 1
 static tdm_error
 _tdm_sprd_pp_queue(tdm_sprd_pp_data *pp_data, unsigned int prop_id,
@@ -401,19 +400,25 @@ static void
 _tdm_sprd_pp_destroy_task(tdm_sprd_pp_data *pp_data, tdm_sprd_pp_task * task)
 {
        int i;
+       tbm_surface_h ret_src_buf = task->buffers[0].src,
+                       ret_dst_buf = task->buffers[task->max_step-1].dst;
 
        for (i = 0; i < task->max_step; i++) {
-               if (task->buffers[i].src)
-                       tbm_surface_internal_unref(task->buffers[i].src);
-               if (task->buffers[i].dst)
-                       tbm_surface_internal_unref(task->buffers[i].dst);
+               if (task->buffers[i].src) {
+                       tdm_buffer_unref_backend(task->buffers[i].src);
+                       task->buffers[i].src = NULL;
+               }
+               if (task->buffers[i].dst) {
+                       tdm_buffer_unref_backend(task->buffers[i].dst);
+                       task->buffers[i].dst = NULL;
+               }
        }
 
        if (task->done_func) {
                TDM_DBG("pp %p(%d). Return src %p dst %p", pp_data, pp_data->stamp,
-                               task->buffers[0].src, task->buffers[task->max_step-1].dst);
-               task->done_func(pp_data, task->buffers[0].src,
-                                               task->buffers[task->max_step-1].dst,
+                               ret_src_buf, ret_dst_buf);
+               task->done_func(pp_data, ret_src_buf,
+                                               ret_dst_buf,
                                                task->done_user_data);
        }
        TDM_DBG("pp %p(%d). Task %p(%d) released", pp_data, pp_data->stamp, task, task->stamp);
@@ -442,11 +447,9 @@ _tdm_sprd_pp_make_new_tasks(tdm_sprd_pp_data *pp_data)
                new_task->max_step = pp_data->roadmap.max_step;
                new_task->current_step = 0;
                new_task->done_func = pp_data->done_func;
-               new_task->done_user_data = pp_data->done_user_data;
-               tbm_surface_internal_ref(main_buffer->src);
-               new_task->buffers[0].src = main_buffer->src;
-               tbm_surface_internal_ref(main_buffer->dst);
-               new_task->buffers[new_task->max_step-1].dst = main_buffer->dst;
+               new_task->done_user_data = pp_data->done_user_data;             
+               new_task->buffers[0].src = tdm_buffer_ref_backend(main_buffer->src);
+               new_task->buffers[new_task->max_step-1].dst = tdm_buffer_ref_backend(main_buffer->dst);
 
 #if 0
                if (new_task->max_step > 1) {
@@ -459,7 +462,7 @@ _tdm_sprd_pp_make_new_tasks(tdm_sprd_pp_data *pp_data)
                        tbm_format temp_buf_fmt = dst_buf_info.format;
                        for (i = 1; i < new_task->max_step; i++) {
                                new_task->buffers[i-1].dst = tbm_surface_create(max_width, max_height, temp_buf_fmt);
-                               tbm_surface_internal_ref(new_task->buffers[i-1].dst);
+                               tdm_buffer_ref_backend(new_task->buffers[i-1].dst);
                                new_task->buffers[i].src = new_task->buffers[i-1].dst;
                        }
                }
@@ -468,8 +471,7 @@ _tdm_sprd_pp_make_new_tasks(tdm_sprd_pp_data *pp_data)
                        new_task->buffers[i-1].dst = tbm_surface_create(pp_data->roadmap.step_info[i-1].dst_config.size.h,
                                                                                                                        pp_data->roadmap.step_info[i-1].dst_config.size.v,
                                                                                                                        pp_data->roadmap.step_info[i-1].dst_config.format);
-                       tbm_surface_internal_ref(new_task->buffers[i-1].dst);
-                       new_task->buffers[i].src = new_task->buffers[i-1].dst;
+                       new_task->buffers[i].src = tdm_buffer_ref_backend(new_task->buffers[i-1].dst);
                        }
                LIST_ADDTAIL(&new_task->link, &pp_data->pending_tasks_list);
                TDM_DBG("pp %p(%d). Add new src %p dst %p buffer", pp_data, pp_data->stamp, main_buffer->src, main_buffer->dst);
@@ -590,7 +592,13 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
                return;
        }
 
-       RETURN_VOID_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data));
+       if(!_tdm_sprd_pp_check_struct(pp_data)) {
+               return;
+       }
+       if (pp_data->pp_need_destroy) {
+               TDM_DBG("pp %p Deferred event of delete", pp_data);
+               return;
+       }
        TDM_DBG("pp %p(%d) index(%d, %d) prop_id(%u)", pp_data, pp_data->stamp, hw_ipp_p->buf_id[0],
                        hw_ipp_p->buf_id[1], hw_ipp_p->prop_id);
        if (!pp_data->first_event) {
@@ -598,13 +606,6 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
                pp_data->first_event = 1;
        }
 
-       if (pp_data->pp_need_destroy) {
-               TDM_DBG("pp %p(%d) Deferred event of delete", pp_data, pp_data->stamp);
-               LIST_DEL(&pp_data->link);
-               free(pp_data);
-               return;
-       }
-
        if ((done_task = pp_data->current_task_p) == NULL) {
                TDM_ERR("pp %p(%d) received wrong event", pp_data, pp_data->stamp);
                return;
@@ -618,7 +619,16 @@ tdm_sprd_pp_handler(struct drm_sprd_ipp_event *hw_ipp_p)
        done_task->status = TASK_DONE;
        TDM_DBG("pp %p(%d). Task %p(%d) done step %d of %d", pp_data, pp_data->stamp, done_task, done_task->stamp,
                        done_task->current_step+1, done_task->max_step);
-
+/*
+       if (pp_data->pp_need_destroy) {
+               TDM_DBG("pp %p(%d) Deferred event of delete", pp_data, pp_data->stamp);
+               _tdm_sprd_pp_destroy_task(pp_data, pp_data->current_task_p);
+               pp_data->current_task_p = NULL;
+               LIST_DEL(&pp_data->link);
+               free(pp_data);
+               return;
+       }
+*/
        if (_tdm_sprd_pp_cmd(pp_data,
                                                 done_task->prop_id[done_task->current_step],
                                                 IPP_PAUSE) != TDM_ERROR_NONE) {
@@ -699,6 +709,9 @@ tdm_sprd_pp_create(tdm_sprd_data *sprd_data, tdm_error *error)
        LIST_INITHEAD(&pp_data->prop_id_list);
        LIST_ADDTAIL(&pp_data->link, &pp_list);
        TDM_DBG("pp %p(%d). Create", pp_data, pp_data->stamp);
+       if (error) {
+               *error = TDM_ERROR_NONE;
+       }
        return pp_data;
 }
 
@@ -711,13 +724,14 @@ sprd_pp_destroy(tdm_pp *pp)
        tdm_sprd_prop_id *prop_id = NULL, *next_prop_id = NULL;
        RETURN_VOID_IF_FAIL(_tdm_sprd_pp_check_struct(pp_data));
        TDM_DBG("pp %p(%d). Destroy", pp_data, pp_data->stamp);
-
+       pp_data->pp_need_destroy = 1;
        LIST_FOR_EACH_ENTRY_SAFE(prop_id, next_prop_id, &pp_data->prop_id_list, link)
                _tdm_sprd_pp_cmd(pp_data, prop_id->prop_id, IPP_STOP);
 
-       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
-               LIST_DEL(&b->link);
-               free(b);
+       if (pp_data->current_task_p) {
+//             TDM_DBG("pp %p(%d) Still converting. Should Remove after callback", pp_data, pp_data->stamp);
+               _tdm_sprd_pp_destroy_task(pp_data, pp_data->current_task_p);
+               pp_data->current_task_p = NULL;
        }
 
        LIST_FOR_EACH_ENTRY_SAFE(task, next_task, &pp_data->pending_tasks_list, link) {
@@ -725,19 +739,17 @@ sprd_pp_destroy(tdm_pp *pp)
                _tdm_sprd_pp_destroy_task(pp_data, task);
        }
 
-       if (pp_data->current_task_p && pp_data->current_task_p->status == TASK_CONVERTING) {
-               TDM_DBG("pp %p(%d) Still converting. Should Remove after callback", pp_data, pp_data->stamp);
-               pp_data->pp_need_destroy = 1;
-               _tdm_sprd_pp_destroy_task(pp_data, pp_data->current_task_p);
-               pp_data->current_task_p = NULL;
+       LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
+               LIST_DEL(&b->link);
+               if (pp_data->done_func)
+                       pp_data->done_func(pp_data, b->src, b->dst,
+                                                               pp_data->done_user_data);
+               free(b);
        }
 
-       if (pp_data->pp_need_destroy)
-               return;
-
+       pp_data->stamp = 0;
        LIST_DEL(&pp_data->link);
        free(pp_data);
-
 }
 
 static tdm_error