diff options
Diffstat (limited to 'src/tdm_vc4_hwc.c')
-rw-r--r-- | src/tdm_vc4_hwc.c | 1050 |
1 files changed, 1050 insertions, 0 deletions
diff --git a/src/tdm_vc4_hwc.c b/src/tdm_vc4_hwc.c new file mode 100644 index 0000000..5924d82 --- /dev/null +++ b/src/tdm_vc4_hwc.c @@ -0,0 +1,1050 @@ +/************************************************************************** + +libtdm_vc4 + +Copyright 2017 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: SooChan Lim <sc1.lim@samsung.com> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_backend_vc4.h" +#include <pixman.h> + +#define NUM_LAYERS 4 +#define NUM_BUFFERS 3 + +#define NUM_UI_LAYERS 2 + +#define ZPOS_MAX 3 +#define ZPOS_CURSOR 2 +#define ZPOS_1 1 +#define ZPOS_0 0 +#define ZPOS_VIDEO1 0 +#define ZPOS_NONE -999 + +tbm_format hwc_window_video_formats[] = { + TBM_FORMAT_NV12, + TBM_FORMAT_YUV420 +}; + +const char * +_comp_to_str(hal_tdm_hwc_window_composition composition_type) +{ + if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_CLIENT) + return "CLIENT"; + else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_DEVICE) + return "DEVICE"; + else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_CURSOR) + return "CURSOR"; + else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_VIDEO) + return "VIDEO"; + else if (composition_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE) + return "SKIP"; + + return "unknown"; +} + +static tbm_surface_queue_h +_vc4_hwc_window_get_tbm_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error) +{ + tdm_vc4_hwc *hwc_data = NULL; + tdm_vc4_hwc_window *hwc_window_data = NULL; + tbm_surface_queue_h tqueue = NULL; + int width, height; + tbm_format format; + + if (error) + *error = HAL_TDM_ERROR_INVALID_PARAMETER; + + hwc_window_data = hwc_window; + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data != NULL, NULL); + + hwc_data = hwc_window_data->hwc_data; + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->output_data != NULL, NULL); + + if (hwc_data->target_hwc_window == hwc_window_data) { + if (hwc_data->output_data->current_mode) { + width = hwc_data->output_data->current_mode->hdisplay; + height = hwc_data->output_data->current_mode->vdisplay; + format = TBM_FORMAT_ARGB8888; + } else { + width = 2; + height = 2; + format = TBM_FORMAT_ARGB8888; + } + } else { + width = hwc_window_data->info.src_config.size.h; + height = hwc_window_data->info.src_config.size.v; + format = hwc_window_data->info.src_config.format; + } + + tqueue = tbm_surface_queue_create(NUM_BUFFERS, width, height, format, TBM_BO_SCANOUT); + if (error) + *error = HAL_TDM_ERROR_OPERATION_FAILED; + TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue != NULL, NULL); + + if (error) + *error = HAL_TDM_ERROR_NONE; + + return tqueue; +} + +static tbm_surface_queue_h +_vc4_hwc_window_get_cursor_tbm_buffer_queue(hal_tdm_hwc_window *hwc_window, hal_tdm_error *error) +{ + tdm_vc4_hwc_window *hwc_window_data = NULL; + tbm_surface_queue_h tqueue = NULL; + int width, height; + + if (error) + *error = HAL_TDM_ERROR_INVALID_PARAMETER; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL); + + hwc_window_data = hwc_window; + + switch (hwc_window_data->info.transform) { + case HAL_TDM_TRANSFORM_90: + case HAL_TDM_TRANSFORM_FLIPPED_90: + case HAL_TDM_TRANSFORM_270: + case HAL_TDM_TRANSFORM_FLIPPED_270: + width = hwc_window_data->cursor_img.height; + height = hwc_window_data->cursor_img.width; + break; + default: + width = hwc_window_data->cursor_img.width; + height = hwc_window_data->cursor_img.height; + break; + } + + tqueue = tbm_surface_queue_create(NUM_BUFFERS, width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); + if (error) + *error = HAL_TDM_ERROR_OPERATION_FAILED; + TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue != NULL, NULL); + + tbm_surface_queue_set_modes(tqueue, TBM_SURFACE_QUEUE_MODE_GUARANTEE_CYCLE); + + if (error) + *error = HAL_TDM_ERROR_NONE; + + return tqueue; +} + +static int +_vc4_hwc_cursor_buffer_image_render(tdm_vc4_hwc *hwc_data, tdm_vc4_hwc_window *hwc_window_data) +{ + tbm_surface_info_s tsurface_info; + tbm_surface_error_e ret = TBM_SURFACE_ERROR_NONE; + void *src_ptr = NULL, *dst_ptr = NULL; + int src_stride, transform, img_w, img_h; + pixman_image_t *src_img = NULL, *dst_img = NULL; + pixman_transform_t t; + struct pixman_f_transform ft; + int c = 0, s = 0, tx = 0, ty = 0; + int i; + + ret = tbm_surface_map(hwc_data->cursor_tsurface, TBM_SURF_OPTION_WRITE, &tsurface_info); + if (ret != TBM_SURFACE_ERROR_NONE) { + TDM_BACKEND_ERR("Failed to map tsurface\n"); + return 0; + } + + src_ptr = hwc_window_data->cursor_img.ptr; + src_stride = hwc_window_data->cursor_img.stride; + img_w = hwc_window_data->cursor_img.width; + img_h = hwc_window_data->cursor_img.height; + transform = hwc_window_data->info.transform; + + dst_ptr = tsurface_info.planes[0].ptr; + + memset(dst_ptr, 0, tsurface_info.planes[0].stride * tsurface_info.height); + + if (transform) { + src_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, img_w, img_h, (uint32_t*)src_ptr, src_stride); + if (!src_img) { + TDM_BACKEND_ERR("Failed to create src pixman\n"); + return 0; + } + + dst_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, tsurface_info.width, tsurface_info.height, + (uint32_t*)dst_ptr, tsurface_info.planes[0].stride); + if (!dst_img) { + TDM_BACKEND_ERR("Failed to create dst pixman\n"); + pixman_image_unref(src_img); + return 0; + } + + pixman_f_transform_init_identity(&ft); + + if (transform >= HAL_TDM_TRANSFORM_FLIPPED) { + pixman_f_transform_scale(&ft, NULL, -1, 1); + pixman_f_transform_translate(&ft, NULL, tsurface_info.width, 0); + } + + switch (transform) { + case HAL_TDM_TRANSFORM_90: + case HAL_TDM_TRANSFORM_FLIPPED_90: + c = 0, s = 1, ty = -tsurface_info.height; + break; + case HAL_TDM_TRANSFORM_180: + case HAL_TDM_TRANSFORM_FLIPPED_180: + c = -1, s = 0, tx = -tsurface_info.width, ty = -tsurface_info.height; + break; + case HAL_TDM_TRANSFORM_270: + case HAL_TDM_TRANSFORM_FLIPPED_270: + c = 0, s = -1, tx = -tsurface_info.width; + break; + default: + break; + } + + pixman_f_transform_translate(&ft, NULL, tx, ty); + pixman_f_transform_rotate(&ft, NULL, c, s); + pixman_transform_from_pixman_f_transform(&t, &ft); + pixman_image_set_transform(src_img, &t); + pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img, 0, 0, 0, 0, 0, 0, + tsurface_info.width, tsurface_info.height); + pixman_image_unref(src_img); + pixman_image_unref(dst_img); + } + else { + for (i = 0 ; i < img_h ; i++) { + memcpy(dst_ptr, src_ptr, src_stride); + dst_ptr += tsurface_info.planes[0].stride; + src_ptr += src_stride; + } + } + + tbm_surface_unmap(hwc_data->cursor_tsurface); + + return 1; +} + +static int +_vc4_hwc_cursor_window_surface_clear(tdm_vc4_hwc_window *hwc_window_data) +{ + hwc_window_data->surface = NULL; + hwc_window_data->cursor_img_surface = 0; + + hwc_window_data->info.src_config.pos.w = hwc_window_data->cursor_img.width; + hwc_window_data->info.src_config.pos.h = hwc_window_data->cursor_img.height; + hwc_window_data->info.dst_pos.w = hwc_window_data->cursor_img.width; + hwc_window_data->info.dst_pos.h = hwc_window_data->cursor_img.height; + + return 1; +} + +static void +_vc4_hwc_cursor_buffer_unset(tdm_vc4_hwc *hwc_data) +{ + if (hwc_data->cursor_tsurface) { + tbm_surface_queue_release(hwc_data->cursor_tqueue, hwc_data->cursor_tsurface); + hwc_data->cursor_tsurface = NULL; + } + + if (hwc_data->cursor_tqueue) { + tbm_surface_queue_destroy(hwc_data->cursor_tqueue); + hwc_data->cursor_tqueue = NULL; + } +} + +static void +_vc4_hwc_cursor_adjust_pos(tdm_vc4_hwc *hwc_data, tdm_vc4_hwc_window *hwc_window_data) +{ + int x, y, width, height; + + width = tbm_surface_get_width(hwc_data->cursor_tsurface); + height = tbm_surface_get_height(hwc_data->cursor_tsurface); + + hwc_window_data->info.src_config.pos.w = width; + hwc_window_data->info.src_config.pos.h = height; + hwc_window_data->info.dst_pos.w = width; + hwc_window_data->info.dst_pos.h = height; + + /* dst pos of cursor is possible set by negative value + * this is temporary code. + */ + x = hwc_window_data->info.dst_pos.x; + y = hwc_window_data->info.dst_pos.y; + + if (x < 0) hwc_window_data->info.dst_pos.x = 0; + if (y < 0) hwc_window_data->info.dst_pos.y = 0; +} + +static int +_vc4_hwc_cursor_buffer_set(tdm_vc4_hwc *hwc_data, tdm_vc4_hwc_window *hwc_window_data) +{ + tbm_surface_h cursor_tsurface = NULL; + tbm_surface_queue_error_e tsq_error = TBM_SURFACE_QUEUE_ERROR_NONE; + int img_w, img_h; + int tqueue_w, tqueue_h; + hal_tdm_error error; + + if (hwc_window_data->cursor_img_refresh || !hwc_window_data->surface) { + switch (hwc_window_data->info.transform) { + case HAL_TDM_TRANSFORM_90: + case HAL_TDM_TRANSFORM_FLIPPED_90: + case HAL_TDM_TRANSFORM_270: + case HAL_TDM_TRANSFORM_FLIPPED_270: + img_w = hwc_window_data->cursor_img.height; + img_h = hwc_window_data->cursor_img.width; + break; + default: + img_w = hwc_window_data->cursor_img.width; + img_h = hwc_window_data->cursor_img.height; + break; + } + + if (!hwc_data->cursor_tqueue) { + hwc_data->cursor_tqueue = _vc4_hwc_window_get_cursor_tbm_buffer_queue(hwc_window_data, &error); + if (error != HAL_TDM_ERROR_NONE) { + TDM_BACKEND_ERR("Failed to create cursor buffer queue error:%d", error); + return 0; + } + } else { + tqueue_w = tbm_surface_queue_get_width(hwc_data->cursor_tqueue); + tqueue_h = tbm_surface_queue_get_height(hwc_data->cursor_tqueue); + if ((img_w != tqueue_w) || (img_h != tqueue_h)) + tbm_surface_queue_reset(hwc_data->cursor_tqueue, img_w, img_h, TBM_FORMAT_ARGB8888); + } + + if (hwc_data->cursor_tsurface) { + tbm_surface_queue_release(hwc_data->cursor_tqueue, hwc_data->cursor_tsurface); + hwc_data->cursor_tsurface = NULL; + } + + if (!tbm_surface_queue_can_dequeue(hwc_data->cursor_tqueue, 0)) { + TDM_BACKEND_ERR("Can't dequeue cursor tqueue"); + return 0; + } + + tsq_error = tbm_surface_queue_dequeue(hwc_data->cursor_tqueue, &cursor_tsurface); + if (tsq_error != TBM_SURFACE_QUEUE_ERROR_NONE) { + TDM_BACKEND_ERR("Failed to dequeue cursor tqueue error:%d", tsq_error); + return 0; + } + + hwc_data->cursor_tsurface = cursor_tsurface; + + _vc4_hwc_cursor_buffer_image_render(hwc_data, hwc_window_data); + + hwc_window_data->surface = cursor_tsurface; + hwc_window_data->cursor_img_surface = 1; + hwc_window_data->cursor_img_refresh = 0; + } + + _vc4_hwc_cursor_adjust_pos(hwc_data, hwc_window_data); + + return 1; +} + +static void +_print_validate_result(tdm_vc4_hwc *hwc_data, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds) +{ + tdm_vc4_hwc_window *hwc_window_data = NULL; + int i; + + for (i = 0; i < num_wnds; i++) { + hwc_window_data = composited_wnds[i]; + switch (hwc_window_data->validated_type) { + case HAL_TDM_HWC_WIN_COMPOSITION_CLIENT: + TDM_BACKEND_DBG(" window(%p) %s -> %s : lzpos(%d) -- {%s} on TARGET WINDOW", hwc_window_data, + _comp_to_str(hwc_window_data->client_type), + _comp_to_str(hwc_window_data->validated_type), + hwc_data->target_hwc_window->lzpos, + hwc_window_data->name ? hwc_window_data->name : "NONE"); + break; + case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE: + case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO: + case HAL_TDM_HWC_WIN_COMPOSITION_CURSOR: + case HAL_TDM_HWC_WIN_COMPOSITION_NONE: + TDM_BACKEND_DBG(" window(%p) %s -> %s : lzpos(%d) -- {%s}", hwc_window_data, + _comp_to_str(hwc_window_data->client_type), + _comp_to_str(hwc_window_data->validated_type), + hwc_window_data->lzpos, + hwc_window_data->name ? hwc_window_data->name : "NONE"); + break; + default: + break; + } + } +} + +static int +_vc4_hwc_window_can_set_on_hw_layer(tdm_vc4_hwc_window *hwc_window_data) +{ + if (!hwc_window_data->surface) + return 0; + + if (hwc_window_data->info.transform != HAL_TDM_TRANSFORM_NORMAL) + return 0; + + if (hwc_window_data->info.src_config.pos.w != hwc_window_data->info.dst_pos.w) + return 0; + + if (hwc_window_data->info.src_config.pos.h != hwc_window_data->info.dst_pos.h) + return 0; + + if (!IS_RGB(hwc_window_data->info.src_config.format)) + return 0; + + if (hwc_window_data->info.dst_pos.x > hwc_window_data->hwc_data->output_data->current_mode->hdisplay || + hwc_window_data->info.dst_pos.y > hwc_window_data->hwc_data->output_data->current_mode->vdisplay) + return 0; + + return 1; +} + +static hal_tdm_error +_vc4_hwc_layer_attach_window(tdm_vc4_layer *layer_data, tdm_vc4_hwc_window *hwc_window_data) +{ + hal_tdm_error ret = HAL_TDM_ERROR_NONE; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(layer_data, HAL_TDM_ERROR_OPERATION_FAILED); + + if (hwc_window_data == NULL || hwc_window_data->surface == NULL) { + if (layer_data->display_buffer) + ret = tdm_vc4_layer_unset_buffer(layer_data); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + + if (layer_data->acquire_fence >= 0) + ret = tdm_vc4_layer_set_acquire_fence(layer_data, -1); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + } else { + ret = tdm_vc4_layer_set_info((tdm_vc4_layer *)layer_data, (tdm_vc4_layer_info *)&(hwc_window_data->info)); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + ret = tdm_vc4_layer_set_buffer(layer_data, hwc_window_data->surface); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + ret = tdm_vc4_layer_set_acquire_fence(layer_data, hwc_window_data->acquire_fence); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + } + + return ret; +} + +static hal_tdm_error +_vc4_hwc_prepare_commit(tdm_vc4_hwc *hwc_data) +{ + tdm_vc4_hwc_window *hwc_window_data = NULL; + tdm_vc4_layer *layer_data = NULL; + int use_layers_zpos[NUM_LAYERS] = {0,}; + int lzpos = 0; + int cursor_enabled = 0; + + /* set target hwc window to the layer_data */ + if (hwc_data->need_target_window) { + layer_data = tdm_vc4_output_get_layer_data(hwc_data->output_data, hwc_data->target_hwc_window->lzpos); + _vc4_hwc_layer_attach_window(layer_data, hwc_data->target_hwc_window); + use_layers_zpos[hwc_data->target_hwc_window->lzpos] = 1; + } + + /* set the hwc_windows to the layers */ + LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) { + if (hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE || + hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_CLIENT) { + if (hwc_window_data->cursor_img_surface) + _vc4_hwc_cursor_window_surface_clear(hwc_window_data); + + continue; + } + + if (hwc_window_data == hwc_data->target_hwc_window) + continue; + + /* set the cursor buffer HERE if it needs */ + if (hwc_window_data->validated_type == HAL_TDM_HWC_WIN_COMPOSITION_CURSOR) { + _vc4_hwc_cursor_buffer_set(hwc_data, hwc_window_data); + cursor_enabled = 1; + } + + layer_data = tdm_vc4_output_get_layer_data(hwc_data->output_data, hwc_window_data->lzpos); + _vc4_hwc_layer_attach_window(layer_data, hwc_window_data); + use_layers_zpos[hwc_window_data->lzpos] = 1; + } + + /* unset the unused layers */ + for (lzpos = 0; lzpos < NUM_LAYERS; lzpos++) { + if (use_layers_zpos[lzpos]) + continue; + + layer_data = tdm_vc4_output_get_layer_data(hwc_data->output_data, lzpos); + if (!layer_data) + continue; + + _vc4_hwc_layer_attach_window(layer_data, NULL); + } + + if (!cursor_enabled) + _vc4_hwc_cursor_buffer_unset(hwc_data); + + /* for debug */ + for (lzpos = NUM_LAYERS -1 ; lzpos >= 0; lzpos--) { + if (use_layers_zpos[lzpos]) + TDM_BACKEND_DBG(" lzpos(%d) : %s", lzpos, use_layers_zpos[lzpos] ? "SET" : "UNSET"); + } + + return HAL_TDM_ERROR_NONE; +} + +/* assign the validated_type to the composited_wnds + * assign the layer_zpos to the composited_wnds + */ +static void +_vc4_hwc_apply_policy(tdm_vc4_hwc *hwc_data , hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds) +{ + tdm_vc4_hwc_window *hwc_window_data = NULL; + tdm_vc4_hwc_window **composited_list = NULL; + int client_count = 0; + int device_count = 0; + int video_count = 0; + int cursor_count = 0; + int ui_lzpos_top = ZPOS_1; + int ui_lzpos_bottom = ZPOS_0; + int num_ui_layers = NUM_UI_LAYERS; + int set_clients_below = 0; + int i = 0; + + composited_list = (tdm_vc4_hwc_window **)composited_wnds; + + /* initialize the need_target_window */ + hwc_data->need_target_window = 0; + + /* initialize the validated_types */ + LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) { + if (hwc_window_data->validated_type != HAL_TDM_HWC_WIN_COMPOSITION_NONE) + hwc_window_data->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_NONE; + } + + /* use the target_window to commit when there is no window. */ + if (num_wnds == 0) { + hwc_data->need_target_window = 1; + hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom; + return; + } + + /* 1. first check validate_type without target_window */ + for (i = 0; i < num_wnds; i++) { + switch (composited_list[i]->client_type) { + case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO: + composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_VIDEO; + video_count++; + num_ui_layers--; + continue; + case HAL_TDM_HWC_WIN_COMPOSITION_CURSOR: + if (set_clients_below) break; + if (cursor_count > 0) break; + + composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CURSOR; + cursor_count++; + continue; + case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE: + if (set_clients_below) break; + if (num_ui_layers <= 0) break; + if (!_vc4_hwc_window_can_set_on_hw_layer(composited_list[i])) break; + + composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_DEVICE; + device_count++; + num_ui_layers--; + continue; + default: + break; + } + + composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT; + client_count++; + set_clients_below = 1; + } + + /* 2. check need target window and set ui_lzpos top and bottom */ + num_ui_layers = NUM_UI_LAYERS; + + if (video_count > 0) { + ui_lzpos_bottom++; + num_ui_layers--; + } + + if ((client_count > 0) || + ((video_count > 0) && (device_count == NUM_UI_LAYERS))) { + ui_lzpos_bottom++; + num_ui_layers--; + hwc_data->need_target_window = 1; + hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom - 1; + } + + if (num_ui_layers > device_count) + ui_lzpos_top = ui_lzpos_bottom + device_count - 1; + + /* 3. set lzpos and modify validate_type with target_window */ + for (i = 0; i < num_wnds; i++) { + switch (composited_list[i]->validated_type) { + case HAL_TDM_HWC_WIN_COMPOSITION_VIDEO: + composited_list[i]->lzpos = ZPOS_VIDEO1; + continue; + case HAL_TDM_HWC_WIN_COMPOSITION_CURSOR: + composited_list[i]->lzpos = ZPOS_CURSOR; + continue; + case HAL_TDM_HWC_WIN_COMPOSITION_DEVICE: + if (num_ui_layers <= 0) break; + composited_list[i]->lzpos = ui_lzpos_top; + ui_lzpos_top--; + num_ui_layers--; + continue; + default: + break; + } + + composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT; + composited_list[i]->lzpos = ZPOS_NONE; + } +} + +static int +_vc4_hwc_get_changed_number(tdm_vc4_hwc *hwc_data) +{ + int num = 0; + tdm_vc4_hwc_window *hwc_window_data = NULL; + + LIST_FOR_EACH_ENTRY(hwc_window_data, &hwc_data->hwc_window_list, link) { + if (hwc_window_data->client_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE) + continue; + + if (hwc_window_data->client_type != hwc_window_data->validated_type) + num++; + } + + return num; +} + +hal_tdm_hwc_window * +_vc4_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_hwc_window_info *info, hal_tdm_error *error) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_hwc_window *hwc_window_data = NULL; + + if (error) + *error = HAL_TDM_ERROR_NONE; + + if (!hwc_data) { + TDM_BACKEND_ERR("invalid params"); + if (error) + *error = HAL_TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + hwc_window_data = calloc(1, sizeof(tdm_vc4_hwc_window)); + if (!hwc_window_data) { + TDM_BACKEND_ERR("alloc failed"); + if (error) + *error = HAL_TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + hwc_window_data->hwc_data = hwc_data; + hwc_window_data->acquire_fence = -1; + + if (info) + memcpy(&hwc_window_data->info, info, sizeof(hal_tdm_hwc_window_info)); + + LIST_INITHEAD(&hwc_window_data->link); + + return hwc_window_data; +} + +hal_tdm_hwc_window * +vc4_hwc_create_window(hal_tdm_hwc *hwc, hal_tdm_error *error) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_hwc_window *hwc_window_data = NULL; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, NULL); + + hwc_window_data = _vc4_hwc_create_window(hwc_data, NULL, error); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_window_data, NULL); + + LIST_ADDTAIL(&hwc_window_data->link, &hwc_data->hwc_window_list); + + TDM_BACKEND_DBG("hwc_window(%p) create", hwc_window_data); + if (error) + *error = HAL_TDM_ERROR_NONE; + + return hwc_window_data; +} + +hal_tdm_error +vc4_hwc_get_video_supported_formats(hal_tdm_hwc *hwc, const tbm_format **formats, int *count) +{ + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(formats != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(count != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + // TODO: fix these formats. + *formats = hwc_window_video_formats; + *count = sizeof(hwc_window_video_formats) / sizeof(tbm_format); + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_get_capabilities(hal_tdm_hwc *hwc, hal_tdm_hwc_capability *capabilities) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_display *display_data = hwc_data->output_data->display_data; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(capabilities != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->output_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + display_data = hwc_data->output_data->display_data; + TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + *capabilities |= HAL_TDM_HWC_CAPABILITY_VIDEO_SCALE; + + if (display_data->has_atomic) + *capabilities |= HAL_TDM_HWC_CAPABILITY_FENCE; + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_get_available_properties(hal_tdm_hwc *hwc, const hal_tdm_prop **props, int *count) +{ + tdm_vc4_hwc *hwc_data = hwc; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(props != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(count != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + *props = NULL; + *count = 0; + + return HAL_TDM_ERROR_NONE; +} + +tbm_surface_queue_h +vc4_hwc_get_client_target_buffer_queue(hal_tdm_hwc *hwc, hal_tdm_error *error) +{ + tdm_vc4_hwc *hwc_data = hwc; + tbm_surface_queue_h tqueue = NULL; + + if (error) + *error = HAL_TDM_ERROR_INVALID_PARAMETER; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL); + + if (hwc_data->target_hwc_window == NULL) { + if (error) + *error = HAL_TDM_ERROR_OPERATION_FAILED; + return NULL; + } + + tqueue = _vc4_hwc_window_get_tbm_buffer_queue(hwc_data->target_hwc_window, error); + TDM_BACKEND_RETURN_VAL_IF_FAIL(tqueue, NULL); + + if (error) + *error = HAL_TDM_ERROR_NONE; + + return tqueue; +} + +hal_tdm_error +vc4_hwc_set_client_target_buffer(hal_tdm_hwc *hwc, tbm_surface_h buffer, hal_tdm_region damage) +{ + tdm_vc4_hwc *hwc_data = hwc; + hal_tdm_error err; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window != NULL, HAL_TDM_ERROR_OPERATION_FAILED); + + err = vc4_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer); + TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err); + + err = vc4_hwc_window_set_buffer_damage(hwc_data->target_hwc_window, damage); + TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err); + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_set_client_target_buffer_info(hal_tdm_hwc *hwc, hal_tdm_hwc_window_info *info) +{ + tdm_vc4_hwc *hwc_data = hwc; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window != NULL, HAL_TDM_ERROR_OPERATION_FAILED); + TDM_BACKEND_RETURN_VAL_IF_FAIL(info != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + if (!memcmp(&hwc_data->target_hwc_window->info, info, sizeof(hal_tdm_hwc_window_info))) + return HAL_TDM_ERROR_NONE; + + hwc_data->target_hwc_window->info = *info; + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_set_client_target_acquire_fence(hal_tdm_hwc *hwc, int acquire_fence) +{ + tdm_vc4_hwc *hwc_data = hwc; + hal_tdm_error err; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window != NULL, HAL_TDM_ERROR_OPERATION_FAILED); + + err = vc4_hwc_window_set_acquire_fence(hwc_data->target_hwc_window, acquire_fence); + TDM_BACKEND_RETURN_VAL_IF_FAIL(err == HAL_TDM_ERROR_NONE, err); + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_validate(hal_tdm_hwc *hwc, hal_tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_output *output_data; + tdm_vc4_hwc_window **composited_list = NULL; + int i; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(num_types != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + TDM_BACKEND_DBG(" ==============Validate================================="); + + /* mirror is set. all clients should be the client type. */ + if (output_data->mirror_dst_output_data) { + composited_list = (tdm_vc4_hwc_window **)composited_wnds; + for (i = 0; i < num_wnds; i++) { + composited_list[i]->validated_type = HAL_TDM_HWC_WIN_COMPOSITION_CLIENT; + } + hwc_data->need_target_window = 1; + hwc_data->target_hwc_window->lzpos = ZPOS_0; + } else { + _vc4_hwc_apply_policy(hwc_data, composited_wnds, num_wnds); + } + + *num_types = _vc4_hwc_get_changed_number(hwc_data); + + _print_validate_result(hwc_data, composited_wnds, num_wnds); + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_get_changed_composition_types(hal_tdm_hwc *hwc, uint32_t *num_elements, + hal_tdm_hwc_window **hwc_wnds, hal_tdm_hwc_window_composition *composition_types) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_hwc_window *hwc_window_data = NULL; + int num = 0; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(num_elements != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + if ((hwc_wnds == NULL) || (composition_types == NULL)) { + *num_elements = _vc4_hwc_get_changed_number(hwc_data); + return HAL_TDM_ERROR_NONE; + } + + LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) { + if (hwc_window_data->client_type == HAL_TDM_HWC_WIN_COMPOSITION_NONE) + continue; + + if (num >= *num_elements) + break; + + if (hwc_window_data->client_type != hwc_window_data->validated_type) { + composition_types[num] = hwc_window_data->validated_type; + hwc_wnds[num] = hwc_window_data; + num++; + } + } + + /* set real num of changed composition types */ + *num_elements = num; + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_accept_validation(hal_tdm_hwc *hwc) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_output *output_data; + hal_tdm_error ret = HAL_TDM_ERROR_NONE; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data->output_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + + TDM_BACKEND_DBG(" ==============Accept Changes Done================================="); + + ret = _vc4_hwc_prepare_commit(hwc_data); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + + /* prepare_mirror_commit for mirroring */ + if (output_data->mirror_dst_output_data) { + ret = tdm_vc4_output_prepare_mirror_commit(output_data->mirror_dst_output_data, + hwc_data->output_data); + if (ret != HAL_TDM_ERROR_NONE) + TDM_BACKEND_ERR("fail to prepare mirror_commit."); + } + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_commit(hal_tdm_hwc *hwc, int sync, void *user_data) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_output *output_data = NULL; + hal_tdm_error ret; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER); + + TDM_BACKEND_DBG(" ==============COMMIT================================="); + + ret = vc4_output_commit(output_data, sync, user_data); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + + /* commit for mirroring */ + if (output_data->mirror_dst_output_data) { + ret = vc4_output_commit(output_data->mirror_dst_output_data, sync, NULL); + TDM_BACKEND_RETURN_VAL_IF_FAIL(ret == HAL_TDM_ERROR_NONE, ret); + } + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_set_commit_handler(hal_tdm_hwc *hwc, hal_tdm_hwc_commit_handler func) +{ + tdm_vc4_hwc *hwc_data = hwc; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER); + + hwc_data->commit_func = func; + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_get_commit_fence(hal_tdm_hwc *hwc, int *commit_fence) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_output *output_data; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(commit_fence, HAL_TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER); + + *commit_fence = dup(output_data->commit_fence); + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +vc4_hwc_get_release_fences(hal_tdm_hwc *hwc, uint32_t *num_elements, + hal_tdm_hwc_window **hwc_wnds, int *fences) +{ + tdm_vc4_hwc *hwc_data = hwc; + tdm_vc4_output *output_data; + tdm_vc4_hwc_window *hwc_window_data = NULL; + int num = 0; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + TDM_BACKEND_RETURN_VAL_IF_FAIL(num_elements != NULL, HAL_TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + TDM_BACKEND_RETURN_VAL_IF_FAIL(output_data, HAL_TDM_ERROR_INVALID_PARAMETER); + + LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) { + if ((hwc_window_data->validated_type != HAL_TDM_HWC_WIN_COMPOSITION_DEVICE) && + (hwc_window_data->validated_type != HAL_TDM_HWC_WIN_COMPOSITION_VIDEO)) + continue; + + if (hwc_wnds && fences) { + fences[num] = dup(output_data->commit_fence); + hwc_wnds[num] = hwc_window_data; + } + + num++; + } + + *num_elements = num; + + return HAL_TDM_ERROR_NONE; +} + +hal_tdm_error +tdm_vc4_hwc_initailize_target_window(tdm_vc4_hwc *hwc_data) +{ + hal_tdm_hwc_window_info info = {0}; + hal_tdm_error ret = HAL_TDM_ERROR_NONE; + tdm_vc4_hwc_window *target_hwc_window; + + TDM_BACKEND_RETURN_VAL_IF_FAIL(hwc_data, HAL_TDM_ERROR_INVALID_PARAMETER); + + info.dst_pos.x = 0; + info.dst_pos.y = 0; + info.dst_pos.w = 2; + info.dst_pos.h = 1; + + info.src_config.pos.x = 0; + info.src_config.pos.y = 0; + info.src_config.pos.w = 2; + info.src_config.pos.h = 1; + + info.src_config.size.h = 2; + info.src_config.size.v = 1; + info.src_config.format = TBM_FORMAT_ARGB8888; + + target_hwc_window = _vc4_hwc_create_window(hwc_data, &info, &ret); + if (ret != HAL_TDM_ERROR_NONE) { + TDM_BACKEND_ERR("create target hwc window failed (%d)", ret); + return HAL_TDM_ERROR_OPERATION_FAILED; + } + + if (hwc_data->target_hwc_window) + vc4_hwc_window_destroy(hwc_data->target_hwc_window); + + hwc_data->target_hwc_window = target_hwc_window; + hwc_data->need_set_crtc = 1; + + return HAL_TDM_ERROR_NONE; +} |