--- /dev/null
+/*
+* Copyright © 2021 Samsung Electronics co., Ltd. All Rights Reserved.
+*
+* 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, sublicense,
+* 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 NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS 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.
+*/
+
+#include "tdm-internal.h"
+
+#define C(b, m) (((b) >> (m)) & 0xFF)
+#define B(c, s) ((((unsigned int)(c)) & 0xff) << (s))
+#define FOURCC(a, b, c, d) (B(d, 24) | B(c, 16) | B(b, 8) | B(a, 0))
+#define FOURCC_STR(id) C(id, 0), C(id, 8), C(id, 16), C(id, 24)
+#define CLEAR(x) memset(&(x), 0, sizeof (x))
+
+enum buffer_type {
+ BUFFER_TYPE_NONE,
+ BUFFER_TYPE_SHM,
+ BUFFER_TYPE_EGL,
+ BUFFER_TYPE_TBM
+};
+
+static pepper_bool_t
+__hwc_window_attach_shm(pepper_tdm_hwc_window_t *hwc_window, pepper_buffer_t *buffer)
+{
+ struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(
+ pepper_buffer_get_resource(buffer));
+
+ if (!shm_buffer)
+ return PEPPER_FALSE;
+
+ hwc_window->shm_buffer = shm_buffer;
+ hwc_window->buffer_width = wl_shm_buffer_get_width(shm_buffer);
+ hwc_window->buffer_height = wl_shm_buffer_get_height(shm_buffer);
+ hwc_window->buffer_type = BUFFER_TYPE_TBM;
+
+ //TODO: make a tbm_surface_h with shm_buffer
+ // and tdm_hwc_window_set_buffer();
+
+ return PEPPER_TRUE;
+}
+
+#ifdef HAVE_TBM
+static pepper_bool_t
+__hwc_window_attach_tbm(pepper_tdm_hwc_window_t *hwc_window, pepper_buffer_t *buffer)
+{
+ tbm_surface_h tbm_surface = wayland_tbm_server_get_surface(NULL,
+ pepper_buffer_get_resource(buffer));
+ tdm_error terror = TDM_ERROR_NONE;
+
+ if (!tbm_surface)
+ return PEPPER_FALSE;
+
+ hwc_window->tbm_surface = tbm_surface;
+ hwc_window->buffer_width = tbm_surface_get_width(tbm_surface);
+ hwc_window->buffer_height = tbm_surface_get_height(tbm_surface);
+ hwc_window->buffer_type = BUFFER_TYPE_TBM;
+
+ terror = tdm_hwc_window_set_buffer(hwc_window->thwc_window, tbm_surface);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE, return PEPPER_FALSE, "tdm_hwc_window_set_buffer() failed.\n");
+
+ return PEPPER_TRUE;;
+}
+#endif
+
+static pepper_bool_t
+__hwc_window_attach_egl(pepper_tdm_hwc_window_t *hwc_window, pepper_buffer_t *buffer)
+{
+#if 0 //TODO: deal with gbm_bo associated with wl_buffer resource???
+ gl_renderer_t *gr = state->renderer;
+ EGLDisplay display = gr->display;
+ struct wl_resource *resource = pepper_buffer_get_resource(buffer);
+
+ gr->query_buffer(display, resource, EGL_WIDTH, &state->buffer_width);
+ gr->query_buffer(display, resource, EGL_HEIGHT, &state->buffer_height);
+ if (!gr->query_buffer(display, resource, EGL_WAYLAND_Y_INVERTED_WL,
+ &state->y_inverted))
+ state->y_inverted = 1;
+
+ state->buffer_type = BUFFER_TYPE_EGL;
+ return PEPPER_TRUE
+#else
+ PEPPER_ERROR("__hwc_window_attach_egl() is not supported\n");
+ return PEPPER_FALSE;
+#endif
+}
+
+static void
+__hwc_window_release_buffer(pepper_tdm_hwc_window_t *hwc_window)
+{
+ if (hwc_window->buffer) {
+ pepper_event_listener_remove(hwc_window->buffer_destroy_listener);
+ hwc_window->buffer = NULL;
+ }
+}
+
+static void
+__hwc_window_handle_buffer_destroy(pepper_event_listener_t *listener,
+ pepper_object_t *object,
+ uint32_t id,
+ void *info,
+ void *data)
+{
+ pepper_tdm_hwc_window_t *hwc_window = data;
+ __hwc_window_release_buffer(hwc_window);
+}
+
+static void
+__hwc_window_handle_surface_destroy(pepper_event_listener_t *listener,
+ pepper_object_t *object,
+ uint32_t id,
+ void *info,
+ void *data)
+{
+ pepper_tdm_hwc_window_t *hwc_window = data;
+
+ PEPPER_INFO("hwc_window:%p thwc_window:%p.\n", hwc_window, hwc_window->thwc_window);
+
+ __hwc_window_release_buffer(hwc_window);
+ pepper_event_listener_remove(hwc_window->surface_destroy_listener);
+ pepper_object_set_user_data((pepper_object_t *)hwc_window->surface, hwc_window->hwc,
+ NULL, NULL);
+
+ tdm_hwc_window_destroy(hwc_window->thwc_window);
+
+ pepper_list_remove(&hwc_window->link);
+ free(hwc_window);
+}
+
+static pepper_tdm_hwc_window_t *
+__get_hwc_window(pepper_tdm_hwc_t *hwc, pepper_surface_t *surface)
+{
+ pepper_tdm_hwc_window_t *hwc_window = pepper_object_get_user_data((
+ pepper_object_t *)surface, hwc);
+
+ if (!hwc_window) {
+ tdm_error terror;
+
+ hwc_window = (pepper_tdm_hwc_window_t *)calloc(1, sizeof(pepper_tdm_hwc_window_t));
+ if (!hwc_window) {
+ PEPPER_ERROR("pepper_tdm_hwc_window_t allocation failed.\n");
+ return NULL;
+ }
+
+ hwc_window->thwc_window = tdm_hwc_create_window(hwc->thwc, &terror);
+ if (!hwc_window->thwc_window) {
+ PEPPER_ERROR("tdm_hwc_create_window() failed.\n");
+ free(hwc_window);
+ return NULL;
+ }
+ hwc_window->tcomposition_type = TDM_HWC_WIN_COMPOSITION_NONE;
+
+ PEPPER_INFO("surface:%p hwc_window:%p thwc_window:%p.\n",
+ surface, hwc_window, hwc_window->thwc_window);
+
+ hwc_window->hwc = (pepper_tdm_hwc_t *)hwc;
+ hwc_window->surface = surface;
+ hwc_window->surface_destroy_listener =
+ pepper_object_add_event_listener((pepper_object_t *)surface,
+ PEPPER_EVENT_OBJECT_DESTROY, 0,
+ __hwc_window_handle_surface_destroy, hwc_window);
+
+ pepper_list_init(&hwc_window->prop_list);
+ pepper_object_set_user_data((pepper_object_t *)surface, hwc, hwc_window, NULL);
+
+ pepper_list_insert(&hwc->window_list, &hwc_window->link);
+ }
+
+ return hwc_window;
+}
+
+pepper_bool_t
+pepper_tdm_hwc_attach_surface(pepper_tdm_hwc_t *hwc, pepper_surface_t *surface)
+{
+ pepper_tdm_hwc_window_t *hwc_window = __get_hwc_window(hwc, surface);
+ pepper_buffer_t *buffer = pepper_surface_get_buffer(surface);
+
+ __hwc_window_release_buffer(hwc_window);
+
+ if (!buffer) {
+ hwc_window->buffer_width = 0;
+ hwc_window->buffer_height = 0;
+ goto done;
+ }
+
+ if (__hwc_window_attach_shm(hwc_window, buffer))
+ goto done;
+
+#ifdef HAVE_TBM
+ if (__hwc_window_attach_tbm(hwc_window, buffer))
+ goto done;
+#endif
+
+ if (__hwc_window_attach_egl(hwc_window, buffer))
+ goto done;
+
+ PEPPER_ERROR("Not supported buffer type.\n");
+ return PEPPER_FALSE;
+
+done:
+ hwc_window->buffer = buffer;
+
+ if (hwc_window->buffer) {
+ hwc_window->buffer_destroy_listener =
+ pepper_object_add_event_listener((pepper_object_t *)buffer,
+ PEPPER_EVENT_OBJECT_DESTROY, 0,
+ __hwc_window_handle_buffer_destroy, hwc_window);
+ }
+
+ return PEPPER_TRUE;
+}
+
+// check the changes of the visible_window_list on hwc
+// check chagnes below
+// - number of visible windows
+// - windows stack
+// - add a window on the list
+// - remove a window on the list
+// - change the order of windows : window stack
+static pepper_bool_t
+__hwc_check_changes_visible_window_list(pepper_tdm_hwc_t *hwc,
+ pepper_list_t *visible_window_list,
+ unsigned int num_visible_wins)
+{
+ pepper_list_t *prev_list;
+ pepper_list_t *curr_list;
+ pepper_tdm_hwc_window_t *hwc_window1, *hwc_window2, *tmp;
+ unsigned int i, cnt;
+
+ // first time
+ if (!hwc->visible_window_list)
+ return PEPPER_TRUE;
+
+ prev_list = hwc->visible_window_list;
+ curr_list = visible_window_list;
+
+ if (hwc->num_visible_wins != num_visible_wins)
+ return PEPPER_TRUE;
+
+ for (i = 0; i < num_visible_wins; i++) {
+ cnt = 0;
+ pepper_list_for_each_safe(hwc_window1, tmp, prev_list, link)
+ if (i == cnt++) break;
+ cnt = 0;
+ pepper_list_for_each_safe(hwc_window2, tmp, curr_list, link)
+ if (i == cnt++) break;
+
+ if (hwc_window1 != hwc_window2) return PEPPER_TRUE;
+ }
+
+ return PEPPER_FALSE;
+}
+
+static void
+__hwc_visible_window_list_destory(pepper_list_t *visible_window_list)
+{
+ pepper_tdm_hwc_window_t *hwc_window, *tmp;
+
+ if (!visible_window_list)
+ return;
+
+ pepper_list_for_each_safe(hwc_window, tmp, visible_window_list, visible_window_link)
+ pepper_list_remove(&hwc_window->visible_window_link);
+
+ free(visible_window_list);
+}
+
+// create a visible window list with a view list
+static pepper_list_t *
+__hwc_create_visible_window_list(pepper_tdm_hwc_t *hwc,
+ const pepper_list_t *view_list,
+ unsigned int *num_visible_wins)
+{
+ pepper_list_t *visible_window_list, *l;
+ pepper_view_t *view;
+ pepper_surface_t *surface;
+ pepper_tdm_hwc_window_t *hwc_window, *hwc_window2;
+
+ visible_window_list = calloc(1, sizeof(pepper_list_t));
+ if (!visible_window_list)
+ return NULL;
+
+ pepper_list_init(visible_window_list);
+
+ // make a visible_window_list
+ // TODO: CHECK Point..
+ // does not add hwc_window to the visible window list
+ // when a pepper_view does not have a pepper_surface because
+ // a hwc_window is only associated with a pepper_surface
+ pepper_list_for_each_list(l, view_list) {
+ view = l->item;
+ surface = pepper_view_get_surface(view);
+ if (!surface)
+ continue;
+
+ hwc_window = pepper_object_get_user_data((pepper_object_t *)surface, hwc);
+ if (!hwc_window)
+ continue;
+
+ hwc_window2 = pepper_object_get_user_data((pepper_object_t *)view, hwc);
+ if (!hwc_window2)
+ pepper_object_set_user_data((pepper_object_t *)view, hwc, hwc_window, NULL);
+
+ PEPPER_INFO("surface:%p view:%p hwc_window:%p thwc_window:%p.\n",
+ surface, view, hwc_window, hwc_window->thwc_window);
+
+ pepper_list_insert(visible_window_list, &hwc_window->visible_window_link);
+ ++(*num_visible_wins);
+ }
+
+ PEPPER_INFO("num_visible_wins curr:%d, necxt:%d\n", hwc->num_visible_wins, num_visible_wins);
+
+ return visible_window_list;
+}
+
+// change the visible window list on hwc with the given visible window list
+static void
+__hwc_change_visible_window_list(pepper_tdm_hwc_t *hwc, pepper_list_t *visible_window_list,
+ unsigned int num_visible_wins)
+{
+ __hwc_visible_window_list_destory(hwc->visible_window_list);
+
+ hwc->num_visible_wins = num_visible_wins;
+ hwc->visible_window_list = visible_window_list;
+}
+
+// update the visible window list on hwc with the given visible view list
+static pepper_bool_t
+__hwc_update_visible_window_list(pepper_tdm_hwc_t *hwc, const pepper_list_t *view_list)
+{
+ pepper_list_t *visible_window_list;
+ unsigned int num_visible_wins = 0;
+
+ // get a visible hwc window list from view list
+ visible_window_list = __hwc_create_visible_window_list(hwc, view_list, &num_visible_wins);
+ if (!visible_window_list)
+ return PEPPER_FALSE;
+
+ // check the changes of the visible windows
+ if (!__hwc_check_changes_visible_window_list(hwc, visible_window_list, num_visible_wins)) {
+ __hwc_visible_window_list_destory(visible_window_list);
+ return PEPPER_FALSE;
+ }
+
+ __hwc_change_visible_window_list(hwc, visible_window_list, num_visible_wins);
+
+ return PEPPER_TRUE;
+}
+
+static void
+__hwc_window_update_composition_type(pepper_tdm_hwc_window_t *hwc_window,
+ tdm_hwc_window_composition tcomposition_type)
+{
+ tdm_error terror;
+
+ if (hwc_window->tcomposition_type == tcomposition_type)
+ return;
+
+ terror = tdm_hwc_window_set_composition_type(hwc_window->thwc_window,
+ tcomposition_type);
+ if (terror != TDM_ERROR_NONE)
+ PEPPER_ERROR("tdm_hwc_window_set_composition failed. hwc_window:%p\n", hwc_window);
+ else
+ hwc_window->tcomposition_type = tcomposition_type;
+}
+
+static pepper_bool_t
+__hwc_window_update_buffer(pepper_tdm_hwc_window_t *hwc_window)
+{
+ tdm_error terror;
+
+ terror = tdm_hwc_window_set_buffer(hwc_window->thwc_window,
+ hwc_window->tbm_surface);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE, return PEPPER_FALSE,
+ "tdm_hwc_window_set_buffer() failed.\n");
+
+ return PEPPER_TRUE;
+}
+
+//TODO: move this function to util file.
+static unsigned int
+__hwc_window_tbm_get_aligned_width_get(tbm_surface_h tsurface)
+{
+ unsigned int aligned_width = 0;
+ tbm_surface_info_s surf_info;
+
+ tbm_surface_get_info(tsurface, &surf_info);
+
+ switch (surf_info.format)
+ {
+ case TBM_FORMAT_YUV420:
+ case TBM_FORMAT_YVU420:
+ case TBM_FORMAT_YUV422:
+ case TBM_FORMAT_YVU422:
+ case TBM_FORMAT_NV12:
+ case TBM_FORMAT_NV21:
+ aligned_width = surf_info.planes[0].stride;
+ break;
+ case TBM_FORMAT_YUYV:
+ case TBM_FORMAT_UYVY:
+ aligned_width = surf_info.planes[0].stride >> 1;
+ break;
+ case TBM_FORMAT_XRGB8888:
+ case TBM_FORMAT_XBGR8888:
+ case TBM_FORMAT_RGBX8888:
+ case TBM_FORMAT_BGRX8888:
+ case TBM_FORMAT_ARGB8888:
+ case TBM_FORMAT_ABGR8888:
+ case TBM_FORMAT_RGBA8888:
+ case TBM_FORMAT_BGRA8888:
+ case TBM_FORMAT_XRGB2101010:
+ case TBM_FORMAT_XBGR2101010:
+ case TBM_FORMAT_RGBX1010102:
+ case TBM_FORMAT_BGRX1010102:
+ case TBM_FORMAT_ARGB2101010:
+ case TBM_FORMAT_ABGR2101010:
+ case TBM_FORMAT_RGBA1010102:
+ case TBM_FORMAT_BGRA1010102:
+ aligned_width = surf_info.planes[0].stride >> 2;
+ break;
+ default:
+ PEPPER_ERROR("not supported format: %c%c%c%c", FOURCC_STR(surf_info.format));
+ }
+
+ return aligned_width;
+}
+
+static pepper_bool_t
+__hwc_window_info_get(pepper_tdm_hwc_window_t *hwc_window, tdm_hwc_window_info *hwc_win_info)
+{
+ tbm_surface_h tsurface = NULL;
+ tbm_surface_info_s surf_info = {0};
+ int x, y, w, h;
+
+ tsurface = hwc_window->tbm_surface;
+ if (!tsurface)
+ return PEPPER_FALSE;
+
+ tbm_surface_get_info(tsurface, &surf_info);
+
+ // make the source infomation
+ hwc_win_info->src_config.format = surf_info.format;
+ hwc_win_info->src_config.pos.x = 0;
+ hwc_win_info->src_config.pos.y = 0;
+ hwc_win_info->src_config.pos.w = surf_info.width;
+ hwc_win_info->src_config.pos.h = surf_info.height;
+
+ hwc_win_info->src_config.size.h = __hwc_window_tbm_get_aligned_width_get(tsurface);
+ PEPPER_CHECK(hwc_win_info->src_config.size.h == 0, return PEPPER_FALSE,
+ "hwc_win_info->src_config.size.h is 0.\n");
+ hwc_win_info->src_config.size.v = surf_info.height;
+
+ // make the destination information
+ // TODO: calculate the result of the tranformation which
+ // is the final dest information from
+ // (buffer_to_surface * surface_to_global * global_to_output).
+ x = 0;
+ y = 0;
+ w = hwc_win_info->src_config.size.h;
+ h = hwc_win_info->src_config.size.v;
+
+ hwc_win_info->dst_pos.x = x;
+ hwc_win_info->dst_pos.y = y;
+ hwc_win_info->dst_pos.w = w;
+ hwc_win_info->dst_pos.h = h;
+
+ hwc_win_info->transform = TDM_TRANSFORM_NORMAL;
+
+ return PEPPER_TRUE;
+}
+
+static pepper_bool_t
+__hwc_window_update_info(pepper_tdm_hwc_window_t *hwc_window)
+{
+ tdm_error terror;
+ tdm_hwc_window_info hwc_win_info;
+
+ // get the hwc information to be updated
+ if (!__hwc_window_info_get(hwc_window, &hwc_win_info))
+ return PEPPER_FALSE;
+
+ // compare the hwc information with current hwc information on hwc_window
+ if (!memcmp(&hwc_window->current.info, &hwc_win_info, sizeof(tdm_hwc_window_info)))
+ return PEPPER_FALSE;
+
+ terror = tdm_hwc_window_set_info(hwc_window->thwc_window, &hwc_window->current.info);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE, return PEPPER_FALSE,
+ "tdm_hwc_window_set_info() failed.\n");
+
+ // change the current hwc information with the hwc inf
+ memcpy(&hwc_window->current.info, &hwc_win_info, sizeof(tdm_hwc_window_info));
+
+ return PEPPER_TRUE;
+}
+
+static pepper_bool_t
+__hwc_window_update_prop(pepper_tdm_hwc_window_t *hwc_window)
+{
+ pepper_tdm_hwc_prop_t *prop, *tmp;
+ tdm_error terror;
+
+ pepper_list_for_each_safe(prop, tmp, &hwc_window->prop_list, link) {
+ terror = tdm_hwc_window_set_property(hwc_window->thwc_window, prop->id, prop->value);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE, return PEPPER_FALSE,
+ "tdm_hwc_window_set_info() failed.\n");
+
+ // delete the prop
+ pepper_list_remove(&prop->link);
+ free(prop);
+ }
+
+ return PEPPER_TRUE;
+}
+
+// TODO: update the composition type of the view
+pepper_bool_t
+pepper_tdm_hwc_update_changes(pepper_tdm_hwc_t *hwc, const pepper_list_t *view_list)
+{
+ pepper_bool_t changed = PEPPER_FALSE;
+ pepper_tdm_hwc_window_t *hwc_window;
+
+ PEPPER_INFO("\n");
+
+ changed = __hwc_update_visible_window_list(hwc, view_list);
+
+ pepper_list_for_each(hwc_window, &hwc->window_list, link) {
+ PEPPER_INFO("hwc_window:%p thwc_window:%p\n", hwc_window, hwc_window->thwc_window);
+
+ // reset the composition types of visible windows
+ __hwc_window_update_composition_type(hwc_window, TDM_HWC_WIN_COMPOSITION_NONE);
+
+ changed = __hwc_window_update_buffer(hwc_window);
+ changed = __hwc_window_update_info(hwc_window);
+ changed = __hwc_window_update_prop(hwc_window);
+ }
+
+ // set the composition types of visible windows
+ // TODO: all gl composite... for verifiying .
+ if (changed) {
+ pepper_list_for_each(hwc_window, hwc->visible_window_list, visible_window_link)
+ __hwc_window_update_composition_type(hwc_window, TDM_HWC_WIN_COMPOSITION_CLIENT);
+ }
+
+ return PEPPER_TRUE;
+}
+
+static pepper_tdm_hwc_window_t *
+__hwc_find_hwc_window_with_thwc_window(pepper_tdm_hwc_t *hwc, tdm_hwc_window *thwc_window)
+{
+ pepper_tdm_hwc_window_t *hwc_window;
+
+ pepper_list_for_each(hwc_window, &hwc->window_list, link) {
+ if (hwc_window->thwc_window == thwc_window) {
+ return hwc_window;
+ }
+ }
+
+ return NULL;
+}
+
+static pepper_bool_t
+__hwc_update_validated_changes(pepper_tdm_hwc_t *hwc, uint32_t num_changes)
+{
+ pepper_tdm_hwc_window_t *hwc_window;
+ tdm_hwc_window **changed_hwc_window = NULL;
+ tdm_hwc_window_composition *composition_types = NULL;
+ tdm_error terror;
+ uint32_t i;
+
+ changed_hwc_window = calloc(num_changes, sizeof(tdm_hwc_window *));
+ PEPPER_CHECK(changed_hwc_window, goto error,
+ "changed_hwc_window allocation failed.\n");
+
+ composition_types = calloc(num_changes, sizeof(tdm_hwc_window_composition));
+ PEPPER_CHECK(composition_types, goto error,
+ "composition_types allocation failed.\n");
+
+ terror = tdm_hwc_get_changed_composition_types(hwc->thwc,
+ &num_changes, changed_hwc_window,
+ composition_types);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE, goto error,
+ "tdm_hwc_get_changed_composition_types() failed.\n");
+
+ // update the tdm compostioin types
+ for (i = 0; i < num_changes; ++i) {
+ hwc_window = __hwc_find_hwc_window_with_thwc_window(hwc, changed_hwc_window[i]);
+ PEPPER_CHECK(hwc_window, goto error,
+ "__hwc_find_hwc_window_with_thwc_window() failed.\n");
+
+ __hwc_window_update_composition_type(hwc_window, composition_types[i]);
+ }
+
+ free(changed_hwc_window);
+ free(composition_types);
+
+ return PEPPER_TRUE;
+
+error:
+ if (changed_hwc_window)
+ free(changed_hwc_window);
+ if (composition_types)
+ free(composition_types);
+
+ return PEPPER_FALSE;
+}
+
+static pepper_bool_t
+__hwc_validate(pepper_tdm_hwc_t *hwc)
+{
+ pepper_tdm_hwc_window_t *hwc_window;
+ tdm_hwc_window **thwc_windows = NULL;
+ tdm_error terror;
+ uint32_t i, n_thw, num_changes;
+ pepper_bool_t ret;
+
+ n_thw = hwc->num_visible_wins;
+ if (n_thw) {
+ thwc_windows = calloc(n_thw, sizeof(tdm_hwc_window *));
+ PEPPER_CHECK(thwc_windows, return PEPPER_FALSE, "thwc_window allocation failed.\n");
+ i = 0;
+ pepper_list_for_each(hwc_window, hwc->visible_window_list, visible_window_link) {
+ PEPPER_INFO("[%d] hwc_window:%p thwc_window:%p\n", i, hwc_window, hwc_window->thwc_window);
+ thwc_windows[i++] = hwc_window->thwc_window;
+ }
+ }
+
+ terror = tdm_hwc_validate(hwc->thwc, thwc_windows, n_thw, &num_changes);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE , goto error, "tdm_hwc_validate() failed.\n");
+
+ if (num_changes > 0) {
+ ret = __hwc_update_validated_changes(hwc, num_changes);
+ PEPPER_CHECK(ret, goto error, "__hwc_update_validated_changes() failed.\n");
+ }
+
+ if (thwc_windows)
+ free(thwc_windows);
+
+ return PEPPER_TRUE;
+
+error:
+ if (thwc_windows)
+ free(thwc_windows);
+
+ return PEPPER_FALSE;
+}
+
+pepper_bool_t
+pepper_tdm_hwc_evaluate(pepper_tdm_hwc_t *hwc, const pepper_list_t *view_list)
+{
+ pepper_tdm_hwc_window_t *hwc_window;
+ pepper_list_t *l;
+ pepper_view_t *view;
+ pepper_bool_t ret;
+ uint32_t num_client = 0, num_device = 0, num_video = 0, num_cursor = 0;
+
+ PEPPER_INFO("\n");
+
+ // validate the hwc_windows on visible_hwc_window
+ ret = __hwc_validate(hwc);
+ PEPPER_CHECK(ret == PEPPER_TRUE, goto error, "__hwc_validate() failed.\n");
+
+ // assign a entry to render when the composition type is client type.
+ pepper_list_for_each_list(l, view_list) {
+ view = l->item;
+ hwc_window = pepper_object_get_user_data((pepper_object_t *)view, hwc);
+ if (!hwc_window) {
+ PEPPER_ERROR("There is no hwc_window from view.\n");
+ continue;
+ }
+
+ if (hwc_window->tcomposition_type != TDM_HWC_WIN_COMPOSITION_CLIENT)
+ continue;
+
+ // assign the entry to target render when the hwc_window of the view has client type.
+ pepper_view_assign_hwc_entry(view, hwc->output->base, PEPPER_TRUE);
+ }
+
+ // count the number of each composition type.
+ pepper_list_for_each(hwc_window, &hwc->window_list, link) {
+ if (hwc_window->tcomposition_type == TDM_HWC_WIN_COMPOSITION_CLIENT)
+ num_client++;
+ if (hwc_window->tcomposition_type == TDM_HWC_WIN_COMPOSITION_DEVICE)
+ num_device++;
+ if (hwc_window->tcomposition_type == TDM_HWC_WIN_COMPOSITION_CURSOR)
+ num_cursor++;
+ if (hwc_window->tcomposition_type == TDM_HWC_WIN_COMPOSITION_VIDEO)
+ num_video++;
+ }
+
+ // TODO: figure out the conditions to re-evaludate the hwc.
+ // set hwc->accept_validation to be PEPPER_FALSE if re-evaluation is needed.
+ // do not call tdm_hwc_accept_validation and tdm_hwc_commit
+ // when hwc->accept_validataion is PEPPER_FALSETRUE.
+ hwc->accept_validation = PEPPER_TRUE;
+
+ return PEPPER_TRUE;
+
+error:
+ hwc->accept_validation = PEPPER_FALSE;
+
+ return PEPPER_FALSE;
+}
+
+static pepper_tdm_hwc_window_commit_data_t *
+__hwc_create_window_commit_data(pepper_tdm_hwc_window_t *hwc_window)
+{
+ pepper_tdm_hwc_window_commit_data_t *window_commit_data;
+
+ window_commit_data = calloc(1, sizeof(pepper_tdm_hwc_window_commit_data_t));
+ PEPPER_CHECK(window_commit_data, return NULL,
+ "commit_data allocation failed.\n");
+ window_commit_data->hwc_window = hwc_window;
+
+ return window_commit_data;
+}
+
+static pepper_tdm_hwc_commit_data_t *
+__hwc_create_commit_data(pepper_tdm_hwc_t *hwc)
+{
+ pepper_tdm_hwc_window_t *hwc_window;
+ pepper_tdm_hwc_commit_data_t *commit_data;
+ pepper_tdm_hwc_window_commit_data_t *window_commit_data;
+
+ commit_data = calloc(1, sizeof(pepper_tdm_hwc_commit_data_t));
+ PEPPER_CHECK(commit_data, goto error,
+ "commit_data allocation failed.\n");
+ commit_data->hwc = hwc;
+
+ pepper_list_init(&commit_data->window_commit_data_list);
+
+ pepper_list_for_each(hwc_window, &hwc->window_list, link) {
+ window_commit_data = __hwc_create_window_commit_data(hwc_window);
+ if (!window_commit_data)
+ continue;
+
+ pepper_list_insert(&commit_data->window_commit_data_list, &window_commit_data->link);
+ }
+
+ return commit_data;
+
+error:
+ if (commit_data)
+ free(commit_data);
+
+ return NULL;
+}
+
+static void
+__hwc_destory_window_commit_data(pepper_tdm_hwc_t *hwc,
+ pepper_tdm_hwc_window_commit_data_t *window_commit_data,
+ unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
+{
+ // TODO: do something here
+
+ pepper_list_remove(&window_commit_data->link);
+ free(window_commit_data);
+}
+
+static void
+__hwc_destroy_commit_data(pepper_tdm_hwc_t *hwc,
+ pepper_tdm_hwc_commit_data_t *commit_data,
+ unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
+{
+ pepper_tdm_hwc_window_commit_data_t *window_commit_data, *tmp;
+
+ pepper_list_for_each_safe(window_commit_data, tmp, &commit_data->window_commit_data_list, link) {
+ // TODO: do something here
+
+ __hwc_destory_window_commit_data(hwc, window_commit_data, sequence, tv_sec, tv_usec);
+ }
+
+ free(commit_data);
+}
+
+static void
+__hwc_commit_handler(tdm_hwc *thwc, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ pepper_tdm_hwc_commit_data_t *commit_data = (pepper_tdm_hwc_commit_data_t *)user_data;
+ // TODO: do something here
+
+ pepper_tdm_output_commit_cb(commit_data->hwc->output, sequence, tv_sec, tv_usec);
+
+ __hwc_destroy_commit_data(commit_data->hwc, commit_data, sequence, tv_sec, tv_usec);
+}
+
+pepper_bool_t
+pepper_tdm_hwc_commit(pepper_tdm_hwc_t *hwc)
+{
+ pepper_tdm_hwc_commit_data_t *commit_data = NULL;
+ tdm_error terror;
+
+ PEPPER_INFO("\n");
+
+ // do not commit when the accept_validateion is not allowed.
+ if (!hwc->accept_validation) {
+ PEPPER_INFO("accept_validation:%d\n", hwc->accept_validation);
+ return PEPPER_TRUE;
+ }
+ hwc->accept_validation = PEPPER_FALSE;
+
+ /* accept validataion */
+ terror = tdm_hwc_accept_validation(hwc->thwc);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE , return PEPPER_FALSE, "tdm_hwc_accept_validation() failed.\n");
+
+ commit_data = __hwc_create_commit_data(hwc);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE , return PEPPER_FALSE, "__hwc_create_commit_data() failed.\n");
+
+ terror = tdm_hwc_commit(hwc->thwc, 0, __hwc_commit_handler, commit_data);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE , goto error, "tdm_hwc_commit() failed.\n");
+
+ return PEPPER_TRUE;
+
+error:
+ if (commit_data)
+ __hwc_destroy_commit_data(hwc, commit_data, 0, 0, 0);
+
+ hwc->accept_validation = PEPPER_FALSE;
+
+ return PEPPER_FALSE;
+}
+
+pepper_bool_t
+pepper_tdm_hwc_set_client_target_buffer(pepper_tdm_hwc_t *hwc, tbm_surface_h tsurface)
+{
+ tdm_region fb_damage;
+ tdm_error terror;
+
+ CLEAR(fb_damage);
+ terror = tdm_hwc_set_client_target_buffer(hwc->thwc, tsurface, fb_damage);
+ PEPPER_CHECK(terror == TDM_ERROR_NONE , return PEPPER_FALSE, "tdm_hwc_set_client_target_buffer() failed.\n");
+
+ return PEPPER_TRUE;
+}