summaryrefslogtreecommitdiff
path: root/src/tdm_vc4_hwc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tdm_vc4_hwc.c')
-rw-r--r--src/tdm_vc4_hwc.c1050
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;
+}