--- /dev/null
+#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, ¢er);
+
+ 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, ¤t_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;
+}
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;
}
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)
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,
_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);
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) {
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;
}
}
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);
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) {
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;
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) {
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;
}
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) {
_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