From: Roman Marchenko Date: Thu, 3 Aug 2017 12:37:08 +0000 (+0300) Subject: hwc: implement the first draft of HWC based on exynos implamantation. X-Git-Tag: accepted/tizen/unified/20180115.074424~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=90832313593015bd3d41e00ce2dc4aec2375495e;p=platform%2Fadaptation%2Fbroadcom%2Flibtdm-vc4.git hwc: implement the first draft of HWC based on exynos implamantation. Change-Id: I1fa0efabb65c890e32c9a8541cabcbb2527b0c16 Signed-off-by: Roman Marchenko --- diff --git a/src/tdm_vc4.c b/src/tdm_vc4.c index 110908f..4c5e801 100644 --- a/src/tdm_vc4.c +++ b/src/tdm_vc4.c @@ -231,7 +231,9 @@ tdm_vc4_init(tdm_display *dpy, tdm_error *error) tdm_func_display vc4_func_display; tdm_func_output vc4_func_output; tdm_func_layer vc4_func_layer; + tdm_func_hwc_window vc4_func_hwc_window; tdm_error ret; + char *str; if (!dpy) { TDM_ERR("display is null"); @@ -255,6 +257,12 @@ tdm_vc4_init(tdm_display *dpy, tdm_error *error) return NULL; } + str = getenv("TDM_HWC"); + if (str) { + char *end; + vc4_data->hwc_mode = strtol(str, &end, 10);; + } + LIST_INITHEAD(&vc4_data->output_list); LIST_INITHEAD(&vc4_data->buffer_list); @@ -280,6 +288,23 @@ tdm_vc4_init(tdm_display *dpy, tdm_error *error) #ifdef HAVE_UDEV vc4_func_output.output_set_status_handler = vc4_output_set_status_handler; #endif + if (vc4_data->hwc_mode) { + vc4_func_output.output_hwc_create_window = vc4_output_hwc_window_create; + vc4_func_output.output_hwc_destroy_window = vc4_output_hwc_window_destroy; + vc4_func_output.output_hwc_validate = vc4_output_hwc_validate; + vc4_func_output.output_hwc_get_changed_composition_types = vc4_output_hwc_get_changed_composition_types; + vc4_func_output.output_hwc_accept_changes = vc4_output_hwc_accept_changes; + vc4_func_output.output_hwc_get_target_buffer_queue = vc4_output_hwc_get_target_buffer_queue; + vc4_func_output.output_hwc_set_client_target_buffer = vc4_output_hwc_set_client_target_buffer; + + memset(&vc4_func_hwc_window, 0, sizeof(vc4_func_hwc_window)); + vc4_func_hwc_window.hwc_window_get_tbm_buffer_queue = vc4_hwc_window_get_tbm_buffer_queue; + vc4_func_hwc_window.hwc_window_set_buffer = vc4_hwc_window_set_buffer; + vc4_func_hwc_window.hwc_window_set_composition_type = vc4_hwc_window_set_composition_type; + vc4_func_hwc_window.hwc_window_set_info = vc4_hwc_window_set_info; + vc4_func_hwc_window.hwc_window_set_buffer_damage = vc4_hwc_window_set_buffer_damage; + vc4_func_hwc_window.hwc_window_set_zpos = vc4_hwc_window_set_zpos; + } memset(&vc4_func_layer, 0, sizeof(vc4_func_layer)); vc4_func_layer.layer_get_capability = vc4_layer_get_capability; @@ -302,6 +327,11 @@ tdm_vc4_init(tdm_display *dpy, tdm_error *error) if (ret != TDM_ERROR_NONE) goto failed; + if (vc4_data->hwc_mode) { + ret = tdm_backend_register_func_hwc_window(dpy, &vc4_func_hwc_window); + if (ret != TDM_ERROR_NONE) + goto failed; + } vc4_data->dpy = dpy; /* The drm master fd can be opened by a tbm backend module in diff --git a/src/tdm_vc4.h b/src/tdm_vc4.h index 6ed6ad3..d0077ac 100644 --- a/src/tdm_vc4.h +++ b/src/tdm_vc4.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,17 @@ tdm_error vc4_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value); tdm_error vc4_output_set_mode(tdm_output *output, const tdm_output_mode *mode); tdm_error vc4_output_get_mode(tdm_output *output, const tdm_output_mode **mode); tdm_error vc4_output_set_status_handler(tdm_output *output, tdm_output_status_handler func, void *user_data); +tdm_hwc_window * vc4_output_hwc_window_create(tdm_output *output, tdm_error *error); +tdm_error vc4_output_hwc_window_destroy(tdm_output *output, tdm_hwc_window *hwc_window); +tdm_error vc4_output_hwc_validate(tdm_output *output, uint32_t *num_types); +tdm_error vc4_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 vc4_output_hwc_accept_changes(tdm_output *output); +tbm_surface_queue_h vc4_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error); +tdm_error vc4_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer, + tdm_hwc_region damage, tdm_hwc_window **composited_wnds, + uint32_t num_wnds); tdm_error vc4_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); tdm_error vc4_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value); tdm_error vc4_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value); @@ -54,6 +66,15 @@ tdm_error vc4_layer_set_info(tdm_layer *layer, tdm_info_layer *info); tdm_error vc4_layer_get_info(tdm_layer *layer, tdm_info_layer *info); tdm_error vc4_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); tdm_error vc4_layer_unset_buffer(tdm_layer *layer); +tdm_error vc4_layer_get_buffer_flags(tdm_layer *layer, unsigned int *flags); +tbm_surface_queue_h vc4_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error); +tdm_error vc4_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos); +tdm_error vc4_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, + tdm_hwc_window_composition composition_type); +tdm_error vc4_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage); +tdm_error vc4_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info); +tdm_error vc4_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface); + /* drm module internal macros, structures, functions */ #define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **") @@ -110,16 +131,18 @@ typedef struct _tdm_vc4_data { drmModeResPtr mode_res; drmModePlaneResPtr plane_res; + int hwc_mode; + struct list_head output_list; struct list_head buffer_list; } tdm_vc4_data; -uint32_t tdm_vc4_format_to_drm_format(tbm_format format); -tbm_format tdm_vc4_format_to_tbm_format(uint32_t format); +uint32_t tdm_vc4_format_to_drm_format(tbm_format format); +tbm_format tdm_vc4_format_to_tbm_format(uint32_t format); -void tdm_vc4_display_update_output_status(tdm_vc4_data *vc4_data); +void tdm_vc4_display_update_output_status(tdm_vc4_data *vc4_data); tdm_error tdm_vc4_display_create_output_list(tdm_vc4_data *vc4_data); -void tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data); +void tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data); tdm_error tdm_vc4_display_create_layer_list(tdm_vc4_data *vc4_data); #endif /* _TDM_VC4_H_ */ diff --git a/src/tdm_vc4_display.c b/src/tdm_vc4_display.c index 00c2c85..b3b93c1 100644 --- a/src/tdm_vc4_display.c +++ b/src/tdm_vc4_display.c @@ -9,8 +9,15 @@ #define MIN_WIDTH 32 +#define LIST_INSERT_AFTER(__after, __item) \ + (__item)->prev = (__after); \ + (__item)->next = (__after)->next; \ + (__after)->next->prev = (__item); \ + (__after)->next = (__item); + typedef struct _tdm_vc4_output_data tdm_vc4_output_data; typedef struct _tdm_vc4_layer_data tdm_vc4_layer_data; +typedef struct _tdm_vc4_hwc_window_data tdm_vc4_hwc_window_data; typedef struct _tdm_vc4_event_data tdm_vc4_event_data; typedef enum { @@ -65,6 +72,17 @@ struct _tdm_vc4_output_data { tbm_surface_h crtc_buffer; int crtc_enabled; unsigned int crtc_fb_id; + + tdm_vc4_hwc_window_data *target_hwc_window; + + int need_validate; + int need_target_buffer; + int hw_layer_count; + int need_set_crtc; + int top_layer_idx; + int hwc_enable; + + struct list_head hwc_window_list; }; struct _tdm_vc4_layer_data { @@ -85,6 +103,33 @@ struct _tdm_vc4_layer_data { int display_buffer_changed; }; +struct _tdm_vc4_hwc_window_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_vc4_data *vc4_data; + tdm_vc4_output_data *output_data; + + /* not fixed data below */ + int zpos; + + tdm_hwc_window_info info; + int info_changed; + + tbm_surface_h surface; + 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 * +_vc4_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, + tdm_error *error); + static drmModeModeInfoPtr _tdm_vc4_display_get_mode(tdm_vc4_output_data *output_data) { @@ -785,6 +830,10 @@ tdm_vc4_display_destroy_output_list(tdm_vc4_data *vc4_data) return; LIST_FOR_EACH_ENTRY_SAFE(o, oo, &vc4_data->output_list, link) { + + if (o->target_hwc_window) + vc4_output_hwc_window_destroy(o, o->target_hwc_window); + if (o->crtc_enabled) { _tdm_vc4_display_set_crtc(vc4_data, o, 0); o->crtc_enabled = 0; @@ -967,6 +1016,12 @@ tdm_vc4_display_create_output_list(tdm_vc4_data *vc4_data) &output_data->output_modes[j]); } + if (vc4_data->hwc_mode) { + output_data->hwc_enable = 1; + output_data->target_hwc_window = NULL; + LIST_INITHEAD(&output_data->hwc_window_list); + } + LIST_ADDTAIL(&output_data->link, &vc4_data->output_list); TDM_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)", @@ -1162,6 +1217,9 @@ vc4_output_get_capability(tdm_output *output, tdm_caps_output *caps) drmModeFreeProperty(prop); } + if (output_data->hwc_enable) + caps->capabilities |= TDM_OUTPUT_CAPABILITY_HWC; + drmModeFreeObjectProperties(props); drmModeFreeCrtc(crtc); drmModeFreeConnector(connector); @@ -1330,6 +1388,100 @@ vc4_output_set_vblank_handler(tdm_output *output, return TDM_ERROR_NONE; } +tdm_vc4_layer_data * +_vc4_output_get_layer(tdm_vc4_output_data *output_data, int index) +{ + tdm_vc4_layer_data *l = NULL; + LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) + if (l->zpos == index) + return l; + + return NULL; +} + +static tdm_error +_vc4_layer_attach_window(tdm_vc4_layer_data *layer_data, + tdm_vc4_hwc_window_data *hwc_window_data) +{ + tdm_error ret; + + if (hwc_window_data == NULL || !hwc_window_data->surface) { + ret = vc4_layer_unset_buffer(layer_data); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + } else { + ret = vc4_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->surface != NULL, TDM_ERROR_INVALID_PARAMETER); + ret = vc4_layer_set_buffer(layer_data, hwc_window_data->surface); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + } + + return ret; +} + +static int +_get_primary_layer_index(tdm_vc4_output_data *vc4_output) +{ + int i = 0; + tdm_vc4_layer_data *layer = NULL; + + LIST_FOR_EACH_ENTRY(layer, &vc4_output->layer_list, link) { + if (layer->capabilities & TDM_LAYER_CAPABILITY_PRIMARY) + return i; + i++; + } + + return 0; +} + +static tdm_error +_tdm_vc4_display_prepare_commit(tdm_vc4_output_data *output_data) { + + tdm_vc4_layer_data * layer = NULL; + tdm_vc4_hwc_window_data *hw = NULL; + int num_hw_layer = 0; + int i; + int fb_idx = 0; + + RETURN_VAL_IF_FAIL(output_data->need_validate == 0, TDM_ERROR_OPERATION_FAILED); + + i = output_data->top_layer_idx; + num_hw_layer = LIST_LENGTH(&output_data->layer_list); + fb_idx = _get_primary_layer_index(output_data); + + //set target hwc window + if (output_data->need_target_buffer) { + layer = _vc4_output_get_layer(output_data, fb_idx); + _vc4_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 (output_data->need_target_buffer && i == fb_idx) { + i--; + } + if (hw->client_type != TDM_COMPOSITION_DEVICE) + continue; + RETURN_VAL_IF_FAIL(i >= 0, TDM_ERROR_OPERATION_FAILED); + layer = _vc4_output_get_layer(output_data, i--); + _vc4_layer_attach_window(layer, hw); + } + + //disable unused layer + while (i >= 0) { + layer = _vc4_output_get_layer(output_data, i--); + _vc4_layer_attach_window(layer, NULL); + } + + i = output_data->top_layer_idx + 1; + while (i < num_hw_layer) { + layer = _vc4_output_get_layer(output_data, i++); + _vc4_layer_attach_window(layer, NULL); + } + + return TDM_ERROR_NONE; +} + tdm_error vc4_output_commit(tdm_output *output, int sync, void *user_data) { @@ -1343,6 +1495,11 @@ vc4_output_commit(tdm_output *output, int sync, void *user_data) vc4_data = output_data->vc4_data; + if (output_data->hwc_enable) { + ret = _tdm_vc4_display_prepare_commit(output_data); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + } + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) { ret = _tdm_vc4_display_commit_layer(layer_data); if (ret != TDM_ERROR_NONE) @@ -1460,9 +1617,41 @@ vc4_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); + if (output_data->hwc_enable) { + + tdm_hwc_window_info info = {0}; + tdm_error ret = TDM_ERROR_NONE; + tdm_vc4_hwc_window_data *target_hwc_window; + + info.dst_pos.x = 0; + info.dst_pos.y = 0; + info.dst_pos.h = mode->vdisplay;; + info.dst_pos.w = mode->hdisplay; + + info.src_config.pos.x = 0; + info.src_config.pos.y = 0; + 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 = _vc4_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) + vc4_output_hwc_window_destroy(output, output_data->target_hwc_window); + + output_data->target_hwc_window = target_hwc_window; + output_data->need_set_crtc = 1; + } + output_data->current_mode = mode; output_data->mode_changed = 1; - return TDM_ERROR_NONE; } @@ -1759,3 +1948,468 @@ vc4_layer_unset_buffer(tdm_layer *layer) return TDM_ERROR_NONE; } + +tdm_error +tdm_vc4_output_insert_hwc_window(tdm_vc4_output_data *output, tdm_vc4_hwc_window_data *hwc_window) +{ + tdm_vc4_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 +_vc4_output_get_changed_number(tdm_vc4_output_data *vc4_output) +{ + int num = 0; + tdm_vc4_hwc_window_data *hw = NULL; + + LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) { + if (hw->client_type != hw->validated_type) + num++; + } + + return num; +} + +tdm_hwc_window * +_vc4_output_hwc_window_create(tdm_output *output, tdm_hwc_window_info *info, tdm_error *error) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = NULL; + tdm_vc4_output_data *vc4_output = output; + + if (error) + *error = TDM_ERROR_NONE; + + if (!vc4_output) { + TDM_ERR("invalid params"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + vc4_hwc_window = calloc(1, sizeof(tdm_vc4_hwc_window_data)); + if (!vc4_hwc_window) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + if ((vc4_hwc_window->vc4_data = vc4_output->vc4_data) == NULL) { + TDM_ERR("invalid params"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + goto fail; + } + + vc4_hwc_window->output_data = output; + vc4_hwc_window->zpos = 0; + + if (info) + memcpy(&vc4_hwc_window->info, info, sizeof(tdm_hwc_window_info)); + + return vc4_hwc_window; +fail: + if (vc4_hwc_window) + free(vc4_hwc_window); + + return NULL; +} + +tdm_hwc_window * +vc4_output_hwc_window_create(tdm_output *output, tdm_error *error) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = NULL; + tdm_vc4_output_data *vc4_output = output; + tdm_error err; + + vc4_hwc_window = _vc4_output_hwc_window_create(vc4_output, NULL, error); + if (vc4_hwc_window == NULL) + return NULL; + + err = tdm_vc4_output_insert_hwc_window(vc4_output, vc4_hwc_window); + if (err != TDM_ERROR_NONE) { + if (error) + *error = err; + free(vc4_hwc_window); + return NULL; + } + + TDM_DBG("hwc_window(%p) create", vc4_hwc_window); + if (error) + *error = TDM_ERROR_NONE; + + return vc4_hwc_window; +} + +tdm_error +vc4_output_hwc_window_destroy(tdm_output *output, tdm_hwc_window *hwc_window) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window; + + LIST_DEL(&vc4_hwc_window->link); + + free(vc4_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"; + + return "unknown"; +} + +tdm_error +vc4_output_hwc_validate(tdm_output *output, uint32_t *num_types) +{ + tdm_vc4_output_data *vc4_output = output; + tdm_vc4_data *vc4_data = NULL; + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER); + tdm_vc4_hwc_window_data *hw = NULL; + int hw_layer_count = 0; + int need_target_buffer = 0; + int max_hw_layer = LIST_LENGTH(&vc4_output->layer_list); + int fb_index = _get_primary_layer_index(vc4_output); + int i = 0; + int top_layer_idx = fb_index; + + vc4_data = vc4_output->vc4_data; + RETURN_VAL_IF_FAIL(vc4_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (vc4_output->need_set_crtc) { + need_target_buffer = 1; + + LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) { + hw->validated_type = TDM_COMPOSITION_CLIENT; + } + } else { + int layer_idx; + int num_hwc_windows = LIST_LENGTH(&vc4_output->hwc_window_list); + + LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) { + hw->validated_type = TDM_COMPOSITION_CLIENT; + } + + /* mark the top window */ + if (num_hwc_windows > 1) { + layer_idx = max_hw_layer; + LIST_FOR_EACH_ENTRY_REV(hw, &vc4_output->hwc_window_list, link) { + layer_idx--; + if (hw->client_type == TDM_COMPOSITION_DEVICE && layer_idx != fb_index) { + //check format + if (IS_RGB(hw->info.src_config.format)) { + hw->validated_type = TDM_COMPOSITION_DEVICE; + hw_layer_count++; + top_layer_idx++; + continue; + } + } + break; + } + } + + if ((num_hwc_windows - hw_layer_count) > (fb_index + 1)) + need_target_buffer = 1; + + max_hw_layer = fb_index + 1; + if (need_target_buffer) + max_hw_layer--; + + /* mark the bottom windows */ + layer_idx = -1; + LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) { + layer_idx++; + /* break if the remaining windows are already marked */ + if (hw->validated_type == TDM_COMPOSITION_DEVICE) + break; + if (hw->client_type == TDM_COMPOSITION_DEVICE && layer_idx < max_hw_layer) { + //check format + if (IS_RGB(hw->info.src_config.format)) { + hw->validated_type = TDM_COMPOSITION_DEVICE; + hw_layer_count++; + continue; + } + } + + need_target_buffer = 1; + break; + } + } + + LIST_FOR_EACH_ENTRY(hw, &vc4_output->hwc_window_list, link) { + if (need_target_buffer && fb_index == i++) + TDM_DBG(" window(%p) target", vc4_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)); + } + + if (need_target_buffer) + hw_layer_count++; + + vc4_output->need_target_buffer = need_target_buffer; + vc4_output->hw_layer_count = hw_layer_count; + vc4_output->top_layer_idx = top_layer_idx; + + *num_types = _vc4_output_get_changed_number(vc4_output); + + if (*num_types == 0) + vc4_output->need_validate = 0; + + return TDM_ERROR_NONE; +} + +tdm_error +vc4_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_vc4_output_data *vc4_output = output; + int num = 0; + + RETURN_VAL_IF_FAIL(vc4_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 = _vc4_output_get_changed_number(vc4_output); + return TDM_ERROR_NONE; + } + + tdm_vc4_hwc_window_data *hw = NULL; + LIST_FOR_EACH_ENTRY_REV(hw, &vc4_output->hwc_window_list, link) { + + 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 +vc4_output_hwc_accept_changes(tdm_output *output) +{ + tdm_vc4_output_data *vc4_output = output; + + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + + tdm_vc4_hwc_window_data *hw = NULL; + LIST_FOR_EACH_ENTRY_REV(hw, &vc4_output->hwc_window_list, link) + hw->client_type = hw->validated_type; + + vc4_output->need_validate = 0; + + return TDM_ERROR_NONE; +} + +tbm_surface_queue_h +vc4_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error) +{ + tdm_vc4_output_data *vc4_output = output; + tbm_surface_queue_h tqueue = NULL; + + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + + RETURN_VAL_IF_FAIL(vc4_output != NULL, NULL); + + if (vc4_output->target_hwc_window == NULL) { + if (error) + *error = TDM_ERROR_OPERATION_FAILED; + return NULL; + } + + tqueue = vc4_hwc_window_get_tbm_buffer_queue(vc4_output->target_hwc_window, error); + RETURN_VAL_IF_FAIL(tqueue, NULL); + + if (error) + *error = TDM_ERROR_NONE; + + return tqueue; +} + +tdm_error +vc4_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer, + tdm_hwc_region damage, tdm_hwc_window **composited_wnds, + uint32_t num_wnds) +{ + tdm_vc4_output_data *vc4_output = output; + tdm_error err; + + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(vc4_output->target_hwc_window != NULL, TDM_ERROR_OPERATION_FAILED); + + err = vc4_hwc_window_set_buffer(vc4_output->target_hwc_window, buffer); + RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err); + + err = vc4_hwc_window_set_buffer_damage(vc4_output->target_hwc_window, damage); + RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err); + + return TDM_ERROR_NONE; +} + + +tbm_surface_queue_h +vc4_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = NULL; + tdm_vc4_output_data *vc4_output = NULL; + tbm_surface_queue_h tqueue = NULL; + tbm_format format; + + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + + RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL); + vc4_hwc_window = hwc_window; + vc4_output = vc4_hwc_window->output_data; + RETURN_VAL_IF_FAIL(vc4_output != NULL, NULL); + + int wight = vc4_hwc_window->info.src_config.size.h; + int hight = vc4_hwc_window->info.src_config.size.v; + + format = vc4_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 +vc4_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window; + tdm_vc4_output_data *vc4_output; + + RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(zpos < 256, TDM_ERROR_INVALID_PARAMETER); + + vc4_output = vc4_hwc_window->output_data; + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (vc4_hwc_window->zpos == zpos) + return TDM_ERROR_NONE; + + LIST_DEL(&vc4_hwc_window->link); + + vc4_hwc_window->zpos = zpos; + + tdm_vc4_output_insert_hwc_window(vc4_output, vc4_hwc_window); + + vc4_output->need_validate = 1; + + return TDM_ERROR_NONE; + +} + +tdm_error +vc4_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, + tdm_hwc_window_composition comp_type) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window; + tdm_vc4_output_data *vc4_output = vc4_hwc_window->output_data; + + RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (vc4_hwc_window->client_type == comp_type) + return TDM_ERROR_NONE; + + vc4_hwc_window->client_type = comp_type; + vc4_output->need_validate = 1; + + return TDM_ERROR_NONE; + +} + +tdm_error +vc4_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window; + tdm_vc4_output_data *vc4_output = vc4_hwc_window->output_data; + + RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + + //TODO:: + + return TDM_ERROR_NONE; +} + +tdm_error +vc4_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window; + tdm_vc4_output_data *vc4_output = vc4_hwc_window->output_data; + + RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(vc4_output != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (!memcmp(&vc4_hwc_window->info, info, sizeof(tdm_hwc_window_info))) + return TDM_ERROR_NONE; + + vc4_hwc_window->info = *info; + vc4_output->need_validate = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +vc4_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface) +{ + tdm_vc4_hwc_window_data *vc4_hwc_window = hwc_window; + tdm_vc4_output_data *vc4_output; + tdm_vc4_data *vc4_data; + tdm_error err = TDM_ERROR_OPERATION_FAILED; + + RETURN_VAL_IF_FAIL(vc4_hwc_window != NULL, err); + + vc4_output = vc4_hwc_window->output_data; + vc4_data = vc4_hwc_window->vc4_data; + + RETURN_VAL_IF_FAIL(vc4_output != NULL, err); + RETURN_VAL_IF_FAIL(vc4_data != NULL, err); + + if (vc4_hwc_window->surface == surface) + return TDM_ERROR_NONE; + + vc4_hwc_window->surface = surface; + + return TDM_ERROR_NONE; +}