From f377c8e4ae01865cfb193ae9a47145125f0d9dbd Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 21 Dec 2020 19:29:25 +0900 Subject: [PATCH] Implementation of TDM_HWC nexell backend supports TDM_HWC. libtdm-nexell operates the displaying buffers with TDM_HWC feature. Change-Id: I6da21f5e21ad71bf7ee21fc2c06b3db738c4bf0f --- src/Makefile.am | 4 +- src/tdm_nexell.c | 68 +++- src/tdm_nexell.h | 93 ++--- src/tdm_nexell_display.c | 672 ++++++++++++++++++++++------------- src/tdm_nexell_hwc.c | 838 ++++++++++++++++++++++++++++++++++++++++++++ src/tdm_nexell_hwc.h | 9 + src/tdm_nexell_hwc_window.c | 227 ++++++++++++ src/tdm_nexell_hwc_window.h | 6 + src/tdm_nexell_types.h | 258 ++++++++++++++ 9 files changed, 1880 insertions(+), 295 deletions(-) create mode 100644 src/tdm_nexell_hwc.c create mode 100644 src/tdm_nexell_hwc.h create mode 100644 src/tdm_nexell_hwc_window.c create mode 100644 src/tdm_nexell_hwc_window.h create mode 100644 src/tdm_nexell_types.h diff --git a/src/Makefile.am b/src/Makefile.am index 296b6a1..f026ba8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,9 @@ libtdm_nexell_la_LDFLAGS = -module -avoid-version libtdm_nexell_la_LIBADD = $(TDM_NEXELL_LIBS) -ldl libtdm_nexell_la_SOURCES = \ + tdm_nexell_display.c \ tdm_nexell_format.c \ + tdm_nexell_hwc_window.c \ + tdm_nexell_hwc.c \ tdm_nexell_pp.c \ - tdm_nexell_display.c \ tdm_nexell.c diff --git a/src/tdm_nexell.c b/src/tdm_nexell.c index a38e294..23c95d3 100644 --- a/src/tdm_nexell.c +++ b/src/tdm_nexell.c @@ -218,6 +218,7 @@ tdm_nexell_deinit(tdm_backend_data *bdata) #endif tdm_nexell_display_destroy_output_list(nexell_data); + tdm_nexell_data_destroy_buffer_list(nexell_data); if (nexell_data->plane_res) drmModeFreePlaneResources(nexell_data->plane_res); @@ -238,10 +239,19 @@ tdm_nexell_init(tdm_display *dpy, tdm_error *error) tdm_func_display nexell_func_display; tdm_func_output nexell_func_output; tdm_func_layer nexell_func_layer; + tdm_func_hwc nexell_func_hwc; + tdm_func_hwc_window nexell_func_hwc_window; #ifdef ENABLE_PP tdm_func_pp nexell_func_pp; #endif tdm_error ret; + char *str; + +#define TDM_CHANGE_DEBUG_LOGLEVEL +#ifdef TDM_CHANGE_DEBUG_LOGLEVEL + // show DBG log level + tdm_log_set_debug_level(4); +#endif if (!dpy) { TDM_ERR("display is null"); @@ -265,6 +275,15 @@ tdm_nexell_init(tdm_display *dpy, tdm_error *error) return NULL; } + str = getenv("TDM_HWC"); + if (str) { + char *end; + nexell_data->hwc_mode = strtol(str, &end, 10);; + } + + /* enable the tdm_hwc */ + nexell_data->hwc_mode = 1; + LIST_INITHEAD(&nexell_data->output_list); LIST_INITHEAD(&nexell_data->buffer_list); @@ -289,10 +308,47 @@ tdm_nexell_init(tdm_display *dpy, tdm_error *error) nexell_func_output.output_get_dpms = nexell_output_get_dpms; nexell_func_output.output_set_mode = nexell_output_set_mode; nexell_func_output.output_get_mode = nexell_output_get_mode; + nexell_func_output.output_set_mirror = NULL; + nexell_func_output.output_unset_mirror = NULL; #ifdef HAVE_UDEV nexell_func_output.output_set_status_handler = nexell_output_set_status_handler; #endif + if (nexell_data->hwc_mode) { + nexell_func_output.output_get_hwc = nexell_output_get_hwc; + + memset(&nexell_func_hwc, 0, sizeof(nexell_func_hwc)); + nexell_func_hwc.hwc_create_window = nexell_hwc_create_window; + nexell_func_hwc.hwc_get_video_supported_formats = nexell_hwc_get_video_supported_formats; + nexell_func_hwc.hwc_get_video_available_properties = NULL; + nexell_func_hwc.hwc_get_capabilities = nexell_hwc_get_capabilities; + nexell_func_hwc.hwc_get_available_properties = nexell_hwc_get_available_properties; + nexell_func_hwc.hwc_get_client_target_buffer_queue = nexell_hwc_get_client_target_buffer_queue; + nexell_func_hwc.hwc_set_client_target_buffer = nexell_hwc_set_client_target_buffer; + nexell_func_hwc.hwc_set_client_target_acquire_fence = NULL; + nexell_func_hwc.hwc_validate = nexell_hwc_validate; + nexell_func_hwc.hwc_get_changed_composition_types = nexell_hwc_get_changed_composition_types; + nexell_func_hwc.hwc_accept_validation = nexell_hwc_accept_validation; + nexell_func_hwc.hwc_commit = nexell_hwc_commit; + nexell_func_hwc.hwc_set_commit_handler = nexell_hwc_set_commit_handler; + nexell_func_hwc.hwc_get_commit_fence = NULL; + nexell_func_hwc.hwc_get_release_fences = NULL; + + memset(&nexell_func_hwc_window, 0, sizeof(nexell_func_hwc_window)); + nexell_func_hwc_window.hwc_window_destroy = nexell_hwc_window_destroy; + nexell_func_hwc_window.hwc_window_acquire_buffer_queue = nexell_hwc_window_acquire_buffer_queue; + nexell_func_hwc_window.hwc_window_release_buffer_queue = nexell_hwc_window_release_buffer_queue; + nexell_func_hwc_window.hwc_window_set_composition_type = nexell_hwc_window_set_composition_type; + nexell_func_hwc_window.hwc_window_set_buffer_damage = nexell_hwc_window_set_buffer_damage; + nexell_func_hwc_window.hwc_window_set_info = nexell_hwc_window_set_info; + nexell_func_hwc_window.hwc_window_set_buffer = nexell_hwc_window_set_buffer; + nexell_func_hwc_window.hwc_window_set_property = nexell_hwc_window_set_property; + nexell_func_hwc_window.hwc_window_get_property = nexell_hwc_window_get_property; + nexell_func_hwc_window.hwc_window_get_constraints = nexell_hwc_window_get_constraints; + nexell_func_hwc_window.hwc_window_set_name = nexell_hwc_window_set_name; + nexell_func_hwc_window.hwc_window_set_cursor_image = nexell_hwc_window_set_cursor_image; + } + memset(&nexell_func_layer, 0, sizeof(nexell_func_layer)); nexell_func_layer.layer_get_capability = nexell_layer_get_capability; nexell_func_layer.layer_set_property = nexell_layer_set_property; @@ -319,6 +375,16 @@ tdm_nexell_init(tdm_display *dpy, tdm_error *error) if (ret != TDM_ERROR_NONE) goto failed; + if (nexell_data->hwc_mode) { + ret = tdm_backend_register_func_hwc(dpy, &nexell_func_hwc); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_hwc_window(dpy, &nexell_func_hwc_window); + if (ret != TDM_ERROR_NONE) + goto failed; + } + ret = tdm_backend_register_func_layer(dpy, &nexell_func_layer); if (ret != TDM_ERROR_NONE) goto failed; @@ -412,7 +478,7 @@ failed: tdm_backend_module tdm_backend_module_data = { "drm", "Samsung", - TDM_BACKEND_SET_ABI_VERSION(1, 1), + TDM_BACKEND_SET_ABI_VERSION(2, 0), tdm_nexell_init, tdm_nexell_deinit }; diff --git a/src/tdm_nexell.h b/src/tdm_nexell.h index 119970a..461ea1d 100644 --- a/src/tdm_nexell.h +++ b/src/tdm_nexell.h @@ -24,6 +24,9 @@ #include #include #include +#include "tdm_nexell_types.h" +#include "tdm_nexell_hwc.h" +#include "tdm_nexell_hwc_window.h" #if HAVE_UDEV #include @@ -49,6 +52,33 @@ tdm_error nexell_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_va tdm_error nexell_output_set_mode(tdm_output *output, const tdm_output_mode *mode); tdm_error nexell_output_get_mode(tdm_output *output, const tdm_output_mode **mode); tdm_error nexell_output_set_status_handler(tdm_output *output, tdm_output_status_handler func, void *user_data); +tdm_hwc *nexell_output_get_hwc(tdm_output *output, tdm_error *error); + +tdm_hwc_window *nexell_hwc_create_window(tdm_hwc *hwc, tdm_error *error); +tdm_error nexell_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count); +tdm_error nexell_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities); +tdm_error nexell_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count); +tbm_surface_queue_h nexell_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error); +tdm_error nexell_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h buffer, tdm_region damage); +tdm_error nexell_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types); +tdm_error nexell_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements, tdm_hwc_window **hwc_wnds, tdm_hwc_window_composition *composition_types); +tdm_error nexell_hwc_accept_validation(tdm_hwc *hwc); +tdm_error nexell_hwc_commit(tdm_hwc *hwc, int sync, void *user_data); +tdm_error nexell_hwc_set_commit_handler(tdm_hwc *hwc, tdm_hwc_commit_handler func); + +void nexell_hwc_window_destroy(tdm_hwc_window *hwc_window); +tdm_error nexell_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, tdm_hwc_window_composition composition_type); +tdm_error nexell_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_region damage); +tdm_error nexell_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info); +tdm_error nexell_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface); +tdm_error nexell_hwc_window_set_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value value); +tdm_error nexell_hwc_window_get_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value *value); +tdm_error nexell_hwc_window_get_constraints(tdm_hwc_window *hwc_window, int *constraints); +tbm_surface_queue_h nexell_hwc_window_acquire_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error); +void nexell_hwc_window_release_buffer_queue(tdm_hwc_window *hwc_window, tbm_surface_queue_h queue); +tdm_error nexell_hwc_window_set_name(tdm_hwc_window *hwc_window, const char *name); +tdm_error nexell_hwc_window_set_cursor_image(tdm_hwc_window *hwc_window, int width, int height, int stride, void *ptr); + tdm_error nexell_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); tdm_error nexell_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value); tdm_error nexell_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value); @@ -62,66 +92,7 @@ tdm_error nexell_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst); tdm_error nexell_pp_commit(tdm_pp *pp); tdm_error nexell_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data); -/* drm module internal macros, structures, functions */ -#define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **") - -#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 IS_RGB(format) (format == TBM_FORMAT_XRGB8888 || format == TBM_FORMAT_ARGB8888 || \ - format == TBM_FORMAT_XBGR8888 || format == TBM_FORMAT_ABGR8888) - -#define CLEAR(x) memset(&(x), 0, sizeof(x)) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define SWAP(a, b) ({int t; t = a; a = b; b = t;}) -#define ROUNDUP(x) (ceil (floor ((float)(height) / 4))) - -#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4) -#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) -#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) -#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11) -#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) -#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16) - -#define RETURN_VAL_IF_FAIL(cond, val) {\ - if (!(cond)) {\ - TDM_ERR("'%s' failed", #cond);\ - return val;\ - }\ -} - -#define GOTO_IF_FAIL(cond, val) {\ - if (!(cond)) {\ - TDM_ERR("'%s' failed", #cond);\ - goto val;\ - }\ -} - -typedef struct _tdm_nexell_data -{ - tdm_display *dpy; - - int drm_fd; - int scaler_fd; - -#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47 - int has_universal_plane; -#endif - -#if HAVE_UDEV - struct udev_monitor *uevent_monitor; - tdm_event_loop_source *uevent_source; -#endif - - drmModeResPtr mode_res; - drmModePlaneResPtr plane_res; - struct list_head output_list; - struct list_head buffer_list; -} tdm_nexell_data; uint32_t tdm_nexell_format_to_drm_format(tbm_format format); tbm_format tdm_nexell_format_to_tbm_format(uint32_t format); @@ -131,5 +102,9 @@ tdm_error tdm_nexell_display_create_output_list(tdm_nexell_data *nexell_data) void tdm_nexell_display_destroy_output_list(tdm_nexell_data *nexell_data); tdm_error tdm_nexell_display_create_layer_list(tdm_nexell_data *nexell_data); +tdm_nexell_layer_data * nexell_output_data_get_layer_data(tdm_nexell_output_data *output_data, int layer_zops); +void tdm_nexell_data_destroy_buffer_list(tdm_nexell_data *nexell_data); +tbm_surface_queue_h tdm_nexell_hwc_window_create_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error); +void tdm_nexell_hwc_window_destroy_tbm_buffer_queue(tbm_surface_queue_h tqueue); #endif /* _TDM_NEXELL_H_ */ diff --git a/src/tdm_nexell_display.c b/src/tdm_nexell_display.c index c20a65a..c2c794e 100644 --- a/src/tdm_nexell_display.c +++ b/src/tdm_nexell_display.c @@ -8,165 +8,8 @@ #include "tdm_nexell.h" #include "tdm_nexell_pp.h" -static int tdm_nexell_buffer_key; -#define TDM_NEXELL_BUFFER_KEY ((unsigned long)&tdm_nexell_buffer_key) - #define MIN_WIDTH 32 -typedef struct _tdm_nexell_output_data tdm_nexell_output_data; -typedef struct _tdm_nexell_layer_data tdm_nexell_layer_data; -typedef struct _tdm_nexell_event_data tdm_nexell_event_data; - -typedef enum { - TDM_NEXELL_EVENT_TYPE_WAIT, - TDM_NEXELL_EVENT_TYPE_COMMIT, - TDM_NEXELL_EVENT_TYPE_PAGEFLIP, -} tdm_nexell_event_type; - -typedef struct _tdm_nexell_display_buffer { - tdm_nexell_data *nexell_data; - unsigned int fb_id; - tbm_surface_h buffer; - int width; -} tdm_nexell_display_buffer; - -struct _tdm_nexell_event_data { - tdm_nexell_event_type type; - tdm_nexell_output_data *output_data; - void *user_data; -}; - -struct _tdm_nexell_output_data { - struct list_head link; - - /* data which are fixed at initializing */ - tdm_nexell_data *nexell_data; - uint32_t connector_id; - uint32_t encoder_id; - uint32_t crtc_id; - uint32_t pipe; - uint32_t dpms_prop_id; - int count_modes; - drmModeModeInfoPtr drm_modes; - tdm_output_mode *output_modes; - tdm_output_type connector_type; - unsigned int connector_type_id; - struct list_head layer_list; - tdm_nexell_layer_data *primary_layer; - - /* not fixed data below */ - tdm_output_vblank_handler vblank_func; - tdm_output_commit_handler commit_func; - - tdm_output_conn_status status; - tdm_output_status_handler status_func; - void *status_user_data; - - int mode_changed; - const tdm_output_mode *current_mode; -}; - -struct _tdm_nexell_layer_data { - struct list_head link; - - /* data which are fixed at initializing */ - tdm_nexell_data *nexell_data; - tdm_nexell_output_data *output_data; - uint32_t plane_id; - tdm_layer_capability capabilities; - int zpos; - - /* not fixed data below */ - tdm_info_layer info; - int info_changed; - - tdm_nexell_display_buffer *display_buffer; - int display_buffer_changed; -}; - -static void -_tdm_nexell_display_buffer_destroy(void *user_data) -{ - tdm_nexell_display_buffer *display_buffer = (tdm_nexell_display_buffer *)user_data; - - if (display_buffer->fb_id > 0) { - int ret = drmModeRmFB(display_buffer->nexell_data->drm_fd, display_buffer->fb_id); - if (ret < 0) { - TDM_ERR("rm fb failed"); - return; - } - TDM_DBG("drmModeRmFB success!!! fb_id:%d", display_buffer->fb_id); - } else - TDM_DBG("drmModeRmFB not called fb_id:%d", display_buffer->fb_id); - - free(display_buffer); -} - -static tdm_nexell_display_buffer * -_tdm_nexell_display_get_buffer(tdm_nexell_data *nexell_data, tbm_surface_h buffer) -{ - tdm_nexell_display_buffer *display_buffer = NULL; - - if (!tbm_surface_internal_get_user_data(buffer, TDM_NEXELL_BUFFER_KEY, (void **)&display_buffer)) { - unsigned int width; - unsigned int height; - unsigned int format; - unsigned int handles[4] = {0,}; - unsigned int pitches[4] = {0,}; - unsigned int offsets[4] = {0,}; - unsigned int size; - tbm_bo bo; - int i, count, ret; - - display_buffer = calloc(1, sizeof(tdm_nexell_display_buffer)); - RETURN_VAL_IF_FAIL(display_buffer != NULL, NULL); - - if (!tbm_surface_internal_add_user_data(buffer, TDM_NEXELL_BUFFER_KEY, _tdm_nexell_display_buffer_destroy)) { - TDM_ERR("FAIL to create user_data for surface %p", buffer); - free(display_buffer); - return NULL; - } - if (!tbm_surface_internal_set_user_data(buffer, TDM_NEXELL_BUFFER_KEY, display_buffer)) { - TDM_ERR("FAIL to set user_data for surface %p", buffer); - tbm_surface_internal_delete_user_data(buffer, TDM_NEXELL_BUFFER_KEY); - free(display_buffer); - return NULL; - } - - display_buffer->nexell_data = nexell_data; - display_buffer->buffer = buffer; - - width = tbm_surface_get_width(buffer); - height = tbm_surface_get_height(buffer); - format = tbm_surface_get_format(buffer); - count = tbm_surface_internal_get_num_planes(format); - bo = tbm_surface_internal_get_bo(buffer, 0); - handles[0] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32; - for (i = 1; i < count; i++) - handles[i] = handles[0]; - - for (i = 0; i < count; i++) - tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]); - - ret = drmModeAddFB2(nexell_data->drm_fd, width, height, format, - handles, pitches, offsets, &display_buffer->fb_id, 0); - if (ret < 0) { - TDM_ERR("add fb failed: %m"); - free(display_buffer); - return NULL; - } - TDM_DBG("nexell_data->drm_fd : %d, display_buffer->fb_id:%u", nexell_data->drm_fd, - display_buffer->fb_id); - - if (IS_RGB(format)) - display_buffer->width = pitches[0] >> 2; - else - display_buffer->width = pitches[0]; - } - - return display_buffer; -} - static drmModeModeInfoPtr _tdm_nexell_display_get_mode(tdm_nexell_output_data *output_data) { @@ -261,6 +104,48 @@ _tdm_nexell_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data) } static tdm_error +_tdm_nexell_display_set_fb(tdm_nexell_data *nexell_data, tbm_surface_h buffer, unsigned int *id) +{ + unsigned int width; + unsigned int height; + unsigned int format; + unsigned int handles[4] = {0,}; + unsigned int pitches[4] = {0,}; + unsigned int offsets[4] = {0,}; + unsigned int size; + unsigned int fb_id; + int ret, count, i; + + width = tbm_surface_get_width(buffer); + height = tbm_surface_get_height(buffer); + format = tbm_surface_get_format(buffer); + count = tbm_surface_internal_get_num_bos(buffer); + for (i = 0; i < count; i++) { + tbm_bo bo = tbm_surface_internal_get_bo(buffer, i); + handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32; + } + count = tbm_surface_internal_get_num_planes(format); + for (i = 0; i < count; i++) + tbm_surface_internal_get_plane_data(buffer, i, &size, &offsets[i], &pitches[i]); + + TDM_DBG("AddFB2: drm_fd(%d) size(%dx%d) format(%c%c%c%c) handles(%d,%d,%d) pitches(%d,%d,%d) offsets(%d,%d,%d) buffer(%p)", + nexell_data->drm_fd, width, height, FOURCC_STR(format), + handles[0], handles[1], handles[2], pitches[0], pitches[1], pitches[2], + offsets[0], offsets[1], offsets[2], buffer); + + ret = drmModeAddFB2(nexell_data->drm_fd, width, height, format, + handles, pitches, offsets, &fb_id, 0); + if (ret < 0) { + TDM_ERR("add fb failed: %m"); + return TDM_ERROR_OPERATION_FAILED; + } + TDM_DBG("AddFB2 success: drm_fd(%d) fb_id(%u)", nexell_data->drm_fd, fb_id); + + *id = fb_id; + return TDM_ERROR_NONE; +} + +static tdm_error _tdm_nexell_output_update_status(tdm_nexell_output_data *output_data, tdm_output_conn_status status) { @@ -279,23 +164,20 @@ _tdm_nexell_output_update_status(tdm_nexell_output_data *output_data, } static tdm_error -_tdm_nexell_display_commit_primary_layer(tdm_nexell_layer_data *layer_data, - void *user_data, int *do_waitvblank) +_tdm_nexell_display_set_crtc(tdm_nexell_data *nexell_data, tdm_nexell_output_data *output_data, int set) { - tdm_nexell_data *nexell_data = layer_data->nexell_data; - tdm_nexell_output_data *output_data = layer_data->output_data; + int ret; - if (output_data->mode_changed && layer_data->display_buffer_changed) { - drmModeModeInfoPtr mode; + output_data->mode_changed = 0; - if (!layer_data->display_buffer) { - TDM_ERR("primary layer should have a buffer for modestting"); - return TDM_ERROR_BAD_REQUEST; - } + if (set) { + tbm_surface_h buffer = NULL; + tbm_surface_info_s info; + drmModeModeInfoPtr mode; + unsigned int fb_id = 0; - output_data->mode_changed = 0; - layer_data->display_buffer_changed = 0; - layer_data->info_changed = 0; + if (!output_data->current_mode) + return TDM_ERROR_OPERATION_FAILED; mode = _tdm_nexell_display_get_mode(output_data); if (!mode) { @@ -303,42 +185,69 @@ _tdm_nexell_display_commit_primary_layer(tdm_nexell_layer_data *layer_data, return TDM_ERROR_BAD_REQUEST; } + /* A buffer which is set to crtc should has TBM_BO_SCANOUT flag */ + buffer = tbm_surface_internal_create_with_flags(output_data->current_mode->hdisplay, + output_data->current_mode->vdisplay, + TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); + RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_OPERATION_FAILED); + + if (tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &info) != TBM_ERROR_NONE) { + tbm_surface_destroy(buffer); + return TDM_ERROR_OPERATION_FAILED; + } + memset(info.planes[0].ptr, 0x0, info.size); + + tbm_surface_unmap(buffer); + + if (_tdm_nexell_display_set_fb(nexell_data, buffer, &fb_id) != TDM_ERROR_NONE) { + tbm_surface_destroy(buffer); + return TDM_ERROR_OPERATION_FAILED; + } + + TDM_DBG("drmModeSetCrtc drm_fd(%d) crtc_id(%u) fb_id(%u) mode(%u,%u)", + nexell_data->drm_fd, output_data->crtc_id, fb_id, + mode->hdisplay, mode->vdisplay); + if (drmModeSetCrtc(nexell_data->drm_fd, output_data->crtc_id, - layer_data->display_buffer->fb_id, 0, 0, - &output_data->connector_id, 1, mode)) { + fb_id, 0, 0, + &output_data->connector_id, 1, mode)) { TDM_ERR("set crtc failed: %m"); + ret = drmModeRmFB(nexell_data->drm_fd, fb_id); + if (ret < 0) + TDM_ERR("rm fb failed fb_id(%u)", fb_id); + tbm_surface_destroy(buffer); return TDM_ERROR_OPERATION_FAILED; } _tdm_nexell_output_update_status(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED); - *do_waitvblank = 1; - return TDM_ERROR_NONE; - } else if (layer_data->display_buffer_changed) { - layer_data->display_buffer_changed = 0; + if (output_data->crtc_buffer) { + ret = drmModeRmFB(nexell_data->drm_fd, output_data->crtc_fb_id); + if (ret < 0) + TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id); + tbm_surface_destroy(output_data->crtc_buffer); + } - if (layer_data->display_buffer) { - tdm_nexell_event_data *event_data = calloc(1, sizeof(tdm_nexell_event_data)); + output_data->crtc_buffer = buffer; + output_data->crtc_fb_id = fb_id; + } else { + TDM_DBG("drmModeSetCrtc unset drm_fd(%d) crtc_id(%u)", + nexell_data->drm_fd, output_data->crtc_id); - if (!event_data) { - TDM_ERR("alloc failed"); - return TDM_ERROR_OUT_OF_MEMORY; - } + if (drmModeSetCrtc(nexell_data->drm_fd, output_data->crtc_id, + 0, 0, 0, NULL, 0, NULL)) { + TDM_ERR("unset crtc failed: %m"); + return TDM_ERROR_OPERATION_FAILED; + } - event_data->type = TDM_NEXELL_EVENT_TYPE_PAGEFLIP; - event_data->output_data = output_data; - event_data->user_data = user_data; - if (drmModePageFlip(nexell_data->drm_fd, output_data->crtc_id, - layer_data->display_buffer->fb_id, DRM_MODE_PAGE_FLIP_EVENT, event_data)) { - TDM_ERR("pageflip failed: %m"); - free(event_data); - return TDM_ERROR_OPERATION_FAILED; - } - *do_waitvblank = 0; + if (output_data->crtc_buffer) { + ret = drmModeRmFB(nexell_data->drm_fd, output_data->crtc_fb_id); + if (ret < 0) + TDM_ERR("rm fb failed fb_id(%u)", output_data->crtc_fb_id); + tbm_surface_destroy(output_data->crtc_buffer); } - }else { - /* to call a user commit handler whenever committed */ - *do_waitvblank = 1; + output_data->crtc_buffer = NULL; + output_data->crtc_fb_id = 0; } return TDM_ERROR_NONE; @@ -355,6 +264,17 @@ _tdm_nexell_display_commit_layer(tdm_nexell_layer_data *layer_data) if (!layer_data->display_buffer_changed && !layer_data->info_changed) return TDM_ERROR_NONE; + // set crtc if crtc is not available and if mode is changed. + if (!output_data->crtc_enabled || output_data->mode_changed) { + if (_tdm_nexell_display_set_crtc(nexell_data, output_data, 1) != TDM_ERROR_NONE) + return TDM_ERROR_OPERATION_FAILED; + + output_data->crtc_enabled = 1; + + return TDM_ERROR_NONE; + } + + // check if the crtc is available if (output_data->current_mode) crtc_w = output_data->current_mode->hdisplay; else { @@ -372,40 +292,42 @@ _tdm_nexell_display_commit_layer(tdm_nexell_layer_data *layer_data) drmModeFreeCrtc(crtc); } + // reset the changed flags layer_data->display_buffer_changed = 0; layer_data->info_changed = 0; - if (!layer_data->display_buffer) { + if (layer_data->display_buffer) { // set plane + /* Source values are 16.16 fixed point */ + fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16; + fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16; + fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16; + fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16; + + TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n", + layer_data->plane_id, output_data->crtc_id, layer_data->zpos, + layer_data->display_buffer->fb_id, + layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y, + layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h, + layer_data->info.dst_pos.x, layer_data->info.dst_pos.y, + layer_data->info.dst_pos.w, layer_data->info.dst_pos.h); + + if (drmModeSetPlane(nexell_data->drm_fd, layer_data->plane_id, + output_data->crtc_id, layer_data->display_buffer->fb_id, 0, + layer_data->info.dst_pos.x, layer_data->info.dst_pos.y, + layer_data->info.dst_pos.w, layer_data->info.dst_pos.h, + fx, fy, fw, fh) < 0) { + TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id); + return TDM_ERROR_OPERATION_FAILED; + } + } else { // unset plane + TDM_DBG("plane(%d) crtc(%d) pos(%d) : unset plane\n", + layer_data->plane_id, output_data->crtc_id, layer_data->zpos); + if (drmModeSetPlane(nexell_data->drm_fd, layer_data->plane_id, output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id); - - return TDM_ERROR_NONE; } - /* Source values are 16.16 fixed point */ - fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16; - fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16; - fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16; - fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16; - - if (drmModeSetPlane(nexell_data->drm_fd, layer_data->plane_id, - output_data->crtc_id, layer_data->display_buffer->fb_id, 0, - layer_data->info.dst_pos.x, layer_data->info.dst_pos.y, - layer_data->info.dst_pos.w, layer_data->info.dst_pos.h, - fx, fy, fw, fh) < 0) { - TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id); - return TDM_ERROR_OPERATION_FAILED; - } - - TDM_DBG("plane(%d) crtc(%d) pos(%d) on: fb(%d,[%d,%d %dx%d]=>[%d,%d %dx%d])\n", - layer_data->plane_id, output_data->crtc_id, layer_data->zpos, - layer_data->display_buffer->fb_id, - layer_data->info.src_config.pos.x, layer_data->info.src_config.pos.y, - layer_data->info.src_config.pos.w, layer_data->info.src_config.pos.h, - layer_data->info.dst_pos.x, layer_data->info.dst_pos.y, - layer_data->info.dst_pos.w, layer_data->info.dst_pos.h); - return TDM_ERROR_NONE; } @@ -416,6 +338,7 @@ _tdm_nexell_display_cb_event(int fd, unsigned int sequence, { tdm_nexell_event_data *event_data = user_data; tdm_nexell_output_data *output_data; + tdm_nexell_hwc_data *hwc_data; if (!event_data) { TDM_ERR("no event data"); @@ -436,9 +359,23 @@ _tdm_nexell_display_cb_event(int fd, unsigned int sequence, event_data->user_data); break; case TDM_NEXELL_EVENT_TYPE_COMMIT: - if (output_data->commit_func) - output_data->commit_func(output_data, sequence, tv_sec, tv_usec, - event_data->user_data); + if (output_data->hwc_enable) { + hwc_data = output_data->hwc_data; + if (!hwc_data) { + TDM_ERR("no hwc_data"); + break; + } + + TDM_DBG("crtc_enable(%d), mode_changed(%d)\n", output_data->crtc_enabled, output_data->mode_changed); + + if (hwc_data->commit_func) + hwc_data->commit_func(hwc_data, sequence, tv_sec, tv_usec, + event_data->user_data); + } else { + if (output_data->commit_func) + output_data->commit_func(output_data, sequence, tv_sec, tv_usec, + event_data->user_data); + } break; default: break; @@ -672,6 +609,7 @@ _tdm_nexell_display_create_layer_list_type(tdm_nexell_data *nexell_data) TDM_LAYER_CAPABILITY_GRAPHIC | TDM_LAYER_CAPABILITY_SCANOUT; layer_data->zpos = cpos_next++; + TDM_INFO("layer_data(%p): cursor zpos(%d)", layer_data, layer_data->zpos); } else if (types[i] == DRM_PLANE_TYPE_OVERLAY) { if (opos_next == 0) { layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY | @@ -689,6 +627,8 @@ _tdm_nexell_display_create_layer_list_type(tdm_nexell_data *nexell_data) } else { layer_data->zpos = opos_next++; } + + TDM_INFO("layer_data(%p): overlay zpos(%d)", layer_data, layer_data->zpos); } else if (types[i] == DRM_PLANE_TYPE_PRIMARY) { layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC | @@ -696,6 +636,8 @@ _tdm_nexell_display_create_layer_list_type(tdm_nexell_data *nexell_data) TDM_LAYER_CAPABILITY_SCANOUT; layer_data->zpos = 1; output_data->primary_layer = layer_data; + + TDM_INFO("layer_data(%p): primary zpos(%d)", layer_data, layer_data->zpos); } else { free(layer_data); continue; @@ -761,11 +703,21 @@ void tdm_nexell_display_destroy_output_list(tdm_nexell_data *nexell_data) { tdm_nexell_output_data *o = NULL, *oo = NULL; + tdm_nexell_hwc_data *hwc_data = NULL; if (LIST_IS_EMPTY(&nexell_data->output_list)) return; LIST_FOR_EACH_ENTRY_SAFE(o, oo, &nexell_data->output_list, link) { + hwc_data = o->hwc_data; + if (hwc_data && hwc_data->target_hwc_window) + nexell_hwc_window_destroy(hwc_data->target_hwc_window); + + if (o->crtc_enabled) { + _tdm_nexell_display_set_crtc(nexell_data, o, 0); + o->crtc_enabled = 0; + } + LIST_DEL(&o->link); if (!LIST_IS_EMPTY(&o->layer_list)) { tdm_nexell_layer_data *l = NULL, *ll = NULL; @@ -980,6 +932,9 @@ tdm_nexell_display_create_output_list(tdm_nexell_data *nexell_data) &output_data->output_modes[j]); } + if (nexell_data->hwc_mode) + output_data->hwc_enable = 1; + LIST_ADDTAIL(&output_data->link, &nexell_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)", @@ -1215,6 +1170,10 @@ nexell_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); @@ -1246,6 +1205,12 @@ nexell_output_get_layers(tdm_output *output, int *count, tdm_error *error) LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) (*count)++; + if (output_data->hwc_enable) { + *count = 0; + ret = TDM_ERROR_NONE; + goto failed_get; + } + if (*count == 0) { ret = TDM_ERROR_NONE; goto failed_get; @@ -1396,6 +1361,7 @@ nexell_output_commit(tdm_output *output, int sync, void *user_data) nexell_data = output_data->nexell_data; +#if 0 LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) { if (layer_data == output_data->primary_layer) { ret = _tdm_nexell_display_commit_primary_layer(layer_data, user_data, @@ -1408,6 +1374,13 @@ nexell_output_commit(tdm_output *output, int sync, void *user_data) return ret; } } +#else + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) { + ret = _tdm_nexell_display_commit_layer(layer_data); + if (ret != TDM_ERROR_NONE) + return ret; + } +#endif if (do_waitvblank == 1) { tdm_nexell_event_data *event_data = calloc(1, sizeof(tdm_nexell_event_data)); @@ -1516,13 +1489,26 @@ tdm_error nexell_output_set_mode(tdm_output *output, const tdm_output_mode *mode) { tdm_nexell_output_data *output_data = output; + tdm_error ret = TDM_ERROR_NONE; RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + /* create or replace the target_window when the output mode is set */ + if (output_data->hwc_enable) { + ret = nexell_hwc_target_window_set_info(output_data->hwc_data, mode->hdisplay, mode->vdisplay); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("set info target hwc window failed (%d)", ret); + return ret; + } + } + output_data->current_mode = mode; output_data->mode_changed = 1; + TDM_INFO("Set the output mode: %s, %d, %d, %d, %d, %d", + mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags, mode->type); + return TDM_ERROR_NONE; } @@ -1539,6 +1525,59 @@ nexell_output_get_mode(tdm_output *output, const tdm_output_mode **mode) return TDM_ERROR_NONE; } +tdm_hwc * +nexell_output_get_hwc(tdm_output *output, tdm_error *error) +{ + tdm_nexell_hwc_data *hwc_data = NULL; + tdm_nexell_output_data *output_data = output; + tdm_error ret = TDM_ERROR_NONE; + + if (!output_data) { + TDM_ERR("invalid params"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (output_data->hwc_data) { + TDM_INFO("hwc_data already exists"); + if (error) + *error = TDM_ERROR_NONE; + return output_data->hwc_data; + } + + hwc_data = calloc(1, sizeof(tdm_nexell_hwc_data)); + if (!hwc_data) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + for (int i = 0; i < NUM_LAYERS; i++) { + hwc_data->ui_buffer_queue[i].tqueue = NULL; + hwc_data->ui_buffer_queue[i].ref_cnt= 0; + } + hwc_data->output_data = output_data; + + LIST_INITHEAD(&hwc_data->hwc_window_list); + + output_data->hwc_data = hwc_data; + + ret = nexell_hwc_initailize_target_window(output_data->hwc_data); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("create target hwc window failed (%d)", ret); + free(hwc_data); + if (error) + *error = ret; + return NULL; + } + + if (error) + *error = TDM_ERROR_NONE; + + return hwc_data; +} + tdm_error nexell_output_set_status_handler(tdm_output *output, tdm_output_status_handler func, @@ -1731,31 +1770,181 @@ nexell_layer_get_info(tdm_layer *layer, tdm_info_layer *info) return TDM_ERROR_NONE; } +static tdm_nexell_display_buffer * +_tdm_nexell_display_find_buffer(tdm_nexell_data *nexell_data, tbm_surface_h buffer) +{ + tdm_nexell_display_buffer *display_buffer = NULL; + + LIST_FOR_EACH_ENTRY(display_buffer, &nexell_data->buffer_list, link) { + if (display_buffer->buffer == buffer) + return display_buffer; + } + + return NULL; +} + +static void +_tdm_nexell_display_cb_destroy_buffer(tbm_surface_h buffer, void *user_data) +{ + tdm_nexell_data *nexell_data; + tdm_nexell_display_buffer *display_buffer; + tdm_nexell_layer_data *layer_data = NULL; + tdm_nexell_output_data *output_data = NULL; + char buf[256] = {0,}; + char *ret_tmp; + + if (!user_data) { + TDM_ERR("no user_data"); + return; + } + if (!buffer) { + TDM_ERR("no buffer"); + return; + } + + nexell_data = (tdm_nexell_data *) user_data; + + display_buffer = _tdm_nexell_display_find_buffer(nexell_data, buffer); + if (!display_buffer) { + TDM_ERR("no display_buffer"); + return; + } + + LIST_FOR_EACH_ENTRY(output_data, &nexell_data->output_list, link) { + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) { + if (display_buffer == layer_data->display_buffer) + layer_data->display_buffer = NULL; + } + } + + if (display_buffer->fb_id > 0) { + if (drmModeRmFB(nexell_data->drm_fd, display_buffer->fb_id) < 0) { + ret_tmp = strerror_r(errno, buf, sizeof(buf)); + TDM_ERR("rm fb failed: %d(%s,%s)\n", errno, buf, ret_tmp); + } + } + + TDM_DBG("destroy buffer:%p", display_buffer->buffer); + + LIST_DEL(&display_buffer->link); + free(display_buffer); +} + +static tdm_nexell_display_buffer * +_tdm_nexell_display_create_buffer(tdm_nexell_data *nexell_data, tbm_surface_h buffer, tdm_error *err) +{ + tdm_nexell_display_buffer *display_buffer = NULL; + tdm_error res = TDM_ERROR_NONE; + int count, i, ret; + + display_buffer = calloc(1, sizeof(tdm_nexell_display_buffer)); + if (!display_buffer) { + TDM_ERR("alloc failed"); + if (err) + *err = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + display_buffer->buffer = buffer; + + res = tdm_buffer_add_destroy_handler(buffer, _tdm_nexell_display_cb_destroy_buffer, nexell_data); + if (res != TDM_ERROR_NONE) { + TDM_ERR("add destroy handler fail"); + free(display_buffer); + if (err) + *err = res; + return NULL; + } + + display_buffer->width = tbm_surface_get_width(buffer); + display_buffer->height = tbm_surface_get_height(buffer); + display_buffer->format = tbm_surface_get_format(buffer); + display_buffer->count = tbm_surface_internal_get_num_bos(buffer); + count = tbm_surface_internal_get_num_planes(display_buffer->format); + TDM_DBG(" display_buffer:%p %dx%d %c%c%c%c bo_num:%d plane_num:%d", + buffer, display_buffer->width, display_buffer->height, + FOURCC_STR(display_buffer->format), display_buffer->count, count); + + for (i = 0; i < count; i++) { + int bo_idx = 0; + tbm_bo bo = NULL; + + bo_idx = tbm_surface_internal_get_plane_bo_idx(buffer, i); + bo = tbm_surface_internal_get_bo(buffer, bo_idx); + display_buffer->handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32; + + tbm_surface_internal_get_plane_data(buffer, i, &display_buffer->size, + &display_buffer->offsets[i], + &display_buffer->pitches[i]); + TDM_DBG("\tplane%d(size:%d offset:%d pitch:%d) bo%d(handle:%d)", + i, display_buffer->size, display_buffer->offsets[i], + display_buffer->pitches[i], bo_idx, display_buffer->handles[i]); + } + + ret = drmModeAddFB2(nexell_data->drm_fd, display_buffer->width, display_buffer->height, + display_buffer->format, display_buffer->handles, display_buffer->pitches, + display_buffer->offsets, &display_buffer->fb_id, 0); + if (ret < 0) { + TDM_ERR("add fb failed: %m"); + free(display_buffer); + if (err) + *err = TDM_ERROR_OPERATION_FAILED; + return NULL; + } + + TDM_DBG("nexell_data->drm_fd : %d, display_buffer->fb_id:%u", nexell_data->drm_fd, + display_buffer->fb_id); + + if (IS_RGB(display_buffer->format)) + display_buffer->width = display_buffer->pitches[0] >> 2; + else + display_buffer->width = display_buffer->pitches[0]; + + LIST_ADDTAIL(&display_buffer->link, &nexell_data->buffer_list); + + if (err) + *err = TDM_ERROR_NONE; + + return display_buffer; +} + +void +tdm_nexell_data_destroy_buffer_list(tdm_nexell_data *nexell_data) +{ + tdm_nexell_display_buffer *b = NULL, *bb = NULL; + + LIST_FOR_EACH_ENTRY_SAFE(b, bb, &nexell_data->buffer_list, link) { + tdm_buffer_remove_destroy_handler(b->buffer, _tdm_nexell_display_cb_destroy_buffer, nexell_data); + _tdm_nexell_display_cb_destroy_buffer(b->buffer, nexell_data); + } +} + tdm_error nexell_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) { tdm_nexell_layer_data *layer_data = layer; tdm_nexell_data *nexell_data; tdm_nexell_display_buffer *display_buffer; + tdm_error err = TDM_ERROR_NONE; RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER); nexell_data = layer_data->nexell_data; - - display_buffer = _tdm_nexell_display_get_buffer(nexell_data, buffer); + display_buffer = _tdm_nexell_display_find_buffer(nexell_data, buffer); if (!display_buffer) { - TDM_ERR("alloc failed"); - return TDM_ERROR_OUT_OF_MEMORY; + display_buffer = _tdm_nexell_display_create_buffer(nexell_data, buffer, &err); + RETURN_VAL_IF_FAIL(display_buffer != NULL, err); } - if (layer_data->display_buffer) - tbm_surface_internal_unref(layer_data->display_buffer->buffer); - - layer_data->display_buffer = display_buffer; - tbm_surface_internal_ref(layer_data->display_buffer->buffer); + if (layer_data->display_buffer != display_buffer) { + if (layer_data->display_buffer) + tbm_surface_internal_unref(layer_data->display_buffer->buffer); - layer_data->display_buffer_changed = 1; + layer_data->display_buffer = display_buffer; + tbm_surface_internal_ref(layer_data->display_buffer->buffer); + layer_data->display_buffer_changed = 1; + } return TDM_ERROR_NONE; } @@ -1776,3 +1965,18 @@ nexell_layer_unset_buffer(tdm_layer *layer) return TDM_ERROR_NONE; } + +tdm_nexell_layer_data * +nexell_output_data_get_layer_data(tdm_nexell_output_data *output_data, int layer_zpos) +{ + tdm_nexell_layer_data *l = NULL; + + RETURN_VAL_IF_FAIL(output_data, NULL); + + LIST_FOR_EACH_ENTRY(l, &output_data->layer_list, link) { + if (l->zpos == layer_zpos) + return l; + } + + return NULL; +} \ No newline at end of file diff --git a/src/tdm_nexell_hwc.c b/src/tdm_nexell_hwc.c new file mode 100644 index 0000000..d80dedb --- /dev/null +++ b/src/tdm_nexell_hwc.c @@ -0,0 +1,838 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "tdm_nexell.h" + +#define MIN_WIDTH 32 + +tbm_format hwc_window_video_formats[] = { + TBM_FORMAT_NV12, + TBM_FORMAT_YUV420 +}; + +const char * +_comp_to_str(tdm_hwc_window_composition composition_type) +{ + if (composition_type == TDM_HWC_WIN_COMPOSITION_CLIENT) + return "CLIENT"; + else if (composition_type == TDM_HWC_WIN_COMPOSITION_DEVICE) + return "DEVICE"; + else if (composition_type == TDM_HWC_WIN_COMPOSITION_CURSOR) + return "CURSOR"; + else if (composition_type == TDM_HWC_WIN_COMPOSITION_VIDEO) + return "VIDEO"; + else if (composition_type == TDM_HWC_WIN_COMPOSITION_NONE) + return "SKIP"; + + return "unknown"; +} + +static int +_nexell_hwc_cursor_buffer_unset(tdm_nexell_hwc_window_data *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 +_nexell_hwc_cursor_adjust_pos(tdm_nexell_hwc_window_data *hwc_window_data) +{ + int x, y; + + /* 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 +_nexell_hwc_cursor_buffer_set(tdm_nexell_hwc_data *hwc_data, tdm_nexell_hwc_window_data *hwc_window_data) +{ + tbm_surface_h cursor_tsurface = NULL; + tbm_surface_info_s tsurface_info; + tbm_surface_error_e ret = TBM_SURFACE_ERROR_NONE; + int img_w, img_h, new_w, new_h; + tbm_format new_format; + unsigned int flags = TBM_BO_SCANOUT; + void *src_ptr = NULL, *dst_ptr = NULL; + int src_stride; + int i; + + _nexell_hwc_cursor_adjust_pos(hwc_window_data); + + if (!hwc_window_data->cursor_img_refresh && hwc_window_data->surface) + return 1; + + img_w = hwc_window_data->cursor_img.width; + img_h = hwc_window_data->cursor_img.height; + new_format = hwc_window_data->info.src_config.format; + + /* cursor restriction to set the cursor layer */ + new_w = (CURSOR_MIN_W > img_w) ? CURSOR_MIN_W : img_w; + new_h = (CURSOR_MIN_H > img_h) ? CURSOR_MIN_H : img_h; + + if (hwc_data->cursor_tsurface) { + tbm_surface_internal_unref(hwc_data->cursor_tsurface); + hwc_data->cursor_tsurface = NULL; + } + + cursor_tsurface = tbm_surface_internal_create_with_flags(new_w, new_h, new_format, flags); + RETURN_VAL_IF_FAIL(cursor_tsurface, 0); + + hwc_data->cursor_tsurface = cursor_tsurface; + ret = tbm_surface_map(hwc_data->cursor_tsurface, TBM_SURF_OPTION_WRITE, &tsurface_info); + if (ret != TBM_SURFACE_ERROR_NONE) { + TDM_ERR("Failed to map tsurface\n"); + tbm_surface_internal_unref(hwc_data->cursor_tsurface); + hwc_data->cursor_tsurface = NULL; + return 0; + } + + src_ptr = hwc_window_data->cursor_img.ptr; + dst_ptr = tsurface_info.planes[0].ptr; + src_stride = hwc_window_data->cursor_img.stride; + + memset(dst_ptr, 0, tsurface_info.planes[0].stride * tsurface_info.height); + + 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); + + hwc_window_data->surface = hwc_data->cursor_tsurface; + hwc_window_data->cursor_img_surface = 1; + + /* fix the dst_pos info of the cursor window */ + hwc_window_data->info.src_config.pos.w = new_w; + hwc_window_data->info.src_config.pos.h = new_h; + hwc_window_data->info.dst_pos.w = new_w; + hwc_window_data->info.dst_pos.h = new_h; + + hwc_window_data->cursor_img_refresh = 0; + + return 1; +} + +static void +_print_validate_result(tdm_nexell_hwc_data *hwc_data, tdm_hwc_window **composited_wnds, uint32_t num_wnds) +{ + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + int i; + int lzpos_queue; + + for (i = 0; i < num_wnds; i++) { + hwc_window_data = composited_wnds[i]; + lzpos_queue = hwc_window_data->lzpos_queue; + switch (hwc_window_data->validated_type) { + case TDM_HWC_WIN_COMPOSITION_CLIENT: + TDM_DBG(" window(%p) %s -> %s : lzpos(%d) lzpos_queue(%d)[tqueue:%p, ref_cnt:%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, + lzpos_queue, lzpos_queue == -1 ? NULL : hwc_data->ui_buffer_queue[lzpos_queue].tqueue, + lzpos_queue == -1 ? 0 : hwc_data->ui_buffer_queue[lzpos_queue].ref_cnt, + hwc_window_data->name ? hwc_window_data->name : "NONE"); + break; + case TDM_HWC_WIN_COMPOSITION_DEVICE: + case TDM_HWC_WIN_COMPOSITION_VIDEO: + case TDM_HWC_WIN_COMPOSITION_CURSOR: + case TDM_HWC_WIN_COMPOSITION_NONE: + TDM_DBG(" window(%p) %s -> %s : lzpos(%d) lzpos_queue(%d)[tqueue:%p ref_cnt:%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, + lzpos_queue, lzpos_queue == -1 ? NULL : hwc_data->ui_buffer_queue[lzpos_queue].tqueue, + lzpos_queue == -1 ? 0 : hwc_data->ui_buffer_queue[lzpos_queue].ref_cnt, + hwc_window_data->name ? hwc_window_data->name : "NONE"); + break; + default: + break; + } + } +} + +static int +_nexell_hwc_window_has_reserved_buffer(tdm_nexell_hwc_window_data *hwc_window_data) { + tbm_bo bo = NULL; + int flags = 0; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, 0); + RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, 0); + + bo = tbm_surface_internal_get_bo(hwc_window_data->surface, 0); + RETURN_VAL_IF_FAIL(bo != NULL, 0); + + flags = tbm_bo_get_flags(bo); + + return flags & TBM_BO_SCANOUT; +} + +static int +_nexell_hwc_window_can_set_on_hw_layer(tdm_nexell_hwc_window_data *hwc_window_data) +{ + if (!hwc_window_data->surface) + return 0; + + if (hwc_window_data->info.transform != 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; + + if (hwc_window_data->info.src_config.pos.w < MIN_WIDTH || hwc_window_data->info.src_config.pos.w % 2) + return 0; + + return 1; +} + +tbm_surface_queue_h +tdm_nexell_hwc_window_create_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error) +{ + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + tbm_surface_queue_h tqueue = NULL; + int width, height; + tbm_format format; + + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + + RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL); + + hwc_window_data = hwc_window; + + 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 = TDM_ERROR_OPERATION_FAILED; + RETURN_VAL_IF_FAIL(tqueue != NULL, NULL); + + if (error) + *error = TDM_ERROR_NONE; + + return tqueue; +} + +void +tdm_nexell_hwc_window_destroy_tbm_buffer_queue(tbm_surface_queue_h tqueue) +{ + tbm_surface_queue_destroy(tqueue); +} + +static tdm_error +_nexell_hwc_layer_attach_window(tdm_nexell_layer_data *layer_data, tdm_nexell_hwc_window_data *hwc_window_data) +{ + tdm_error ret = TDM_ERROR_NONE; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED); + + if (hwc_window_data == NULL || hwc_window_data->surface == NULL) { + if (layer_data->display_buffer) + ret = nexell_layer_unset_buffer(layer_data); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + } else { + ret = nexell_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 = nexell_layer_set_buffer(layer_data, hwc_window_data->surface); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + } + + return ret; +} + +static tdm_error +_nexell_hwc_prepare_commit(tdm_nexell_hwc_data *hwc_data) +{ + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + tdm_nexell_layer_data *layer_data = NULL; + int use_layers_zpos[NUM_LAYERS] = {0,}; + int lzpos = 0; + + /* set target hwc window to the layer */ + if (hwc_data->need_target_window) { + layer_data = nexell_output_data_get_layer_data(hwc_data->output_data, hwc_data->target_hwc_window->lzpos); + _nexell_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 == TDM_HWC_WIN_COMPOSITION_NONE || + hwc_window_data->validated_type == TDM_HWC_WIN_COMPOSITION_CLIENT) { + + if (hwc_window_data->cursor_img_surface) + _nexell_hwc_cursor_buffer_unset(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 == TDM_HWC_WIN_COMPOSITION_CURSOR) + _nexell_hwc_cursor_buffer_set(hwc_data, hwc_window_data); + + layer_data = nexell_output_data_get_layer_data(hwc_data->output_data, hwc_window_data->lzpos); + _nexell_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 = nexell_output_data_get_layer_data(hwc_data->output_data, lzpos); + if (!layer_data) + continue; + + _nexell_hwc_layer_attach_window(layer_data, NULL); + } + + /* for debug */ + for (lzpos = NUM_LAYERS -1 ; lzpos >= 0; lzpos--) { + if (use_layers_zpos[lzpos]) + TDM_DBG(" lzpos(%d) : %s", lzpos, use_layers_zpos[lzpos] ? "SET" : "UNSET"); + } + + return TDM_ERROR_NONE; +} + +/* assign the validated_type to the composited_wnds + * assign the layer_zpos to the composited_wnds + */ +static void +_nexell_hwc_apply_policy(tdm_nexell_hwc_data *hwc_data , tdm_hwc_window **composited_wnds, uint32_t num_wnds) +{ + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + tdm_nexell_hwc_window_data **composited_list = NULL; + int client_count = 0; + int device_count = 0; + int video_count = 0; + int cursor_count = 0; + int i = 0; + int top_index = 0; // index of top in composited_wnds + int bottom_index = num_wnds - 1; // index of bottom in comopsited_wnds + int available_device_num = NUM_LAYERS; + int use_hw_layers[NUM_LAYERS] = {0, }; // 2 is top, 0 is bottom + + composited_list = (tdm_nexell_hwc_window_data **)composited_wnds; + +static int cnt = 0; + + // for debugging + for (i = 0; i < num_wnds; i++) { + TDM_DBG(" [%d] name(%s)", i, composited_list[i]->name); + composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_NONE; + composited_list[i]->lzpos = -1; + composited_list[i]->lzpos_queue = -1; + + ++cnt; + if (cnt < 10) + goto set_clients_below; + } + + /* initialize the need_target_window */ + hwc_data->need_target_window = 0; + + /* initialize the validated_types and constraints */ + LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) { + hwc_window_data->constraints = TDM_HWC_WIN_CONSTRAINT_NONE; + if (hwc_window_data->validated_type == TDM_HWC_WIN_COMPOSITION_NONE) + continue; + hwc_window_data->validated_type = TDM_HWC_WIN_COMPOSITION_NONE; + hwc_window_data->lzpos = -1; + hwc_window_data->lzpos_queue = -1; + } + + /* 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 = ZPOS_1; + hwc_data->target_hwc_window->lzpos_queue = ZPOS_1; + return; + } + + /* count the composited(visible) windows */ + for (i = 0; i < num_wnds; i++) { + if (composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_CURSOR) + cursor_count++; + if (composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_CLIENT) + client_count++; + if (client_count == 0 && composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_DEVICE) + device_count++; + if (composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_VIDEO) + video_count++; + } + + /* set the cursor layer pos and validated_type */ + if (cursor_count > 0) { + composited_list[top_index]->validated_type = TDM_HWC_WIN_COMPOSITION_CURSOR; + composited_list[top_index]->lzpos = ZPOS_2; + use_hw_layers[ZPOS_2] = 1; + available_device_num--; + } + + /* set the video layer pos and validated_type */ + if (video_count > 0) { + composited_list[bottom_index]->validated_type = TDM_HWC_WIN_COMPOSITION_VIDEO; + composited_list[bottom_index]->lzpos = ZPOS_0; + use_hw_layers[ZPOS_0] = 1; + available_device_num--; + } + + /* check if target_window is needed */ + if (client_count > 0) { + hwc_data->need_target_window = 1; + use_hw_layers[ZPOS_1] = 1; // target_window must set to ZPOS_1 because it is primary layer. + available_device_num--; + } + + /* set all client types when the number of devide types is over than available device_num */ + if (available_device_num <= 0) + goto set_clients_below; + + int lzpos = -1; + int j; + for (i = 0; i < num_wnds; i++) { + if (composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_CURSOR) + continue; + if (composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_CLIENT) + goto set_clients_below; + if (composited_list[i]->client_type == TDM_HWC_WIN_COMPOSITION_VIDEO) + break; + + /* set clients below when nexell can not set the window to the hw layer */ + if (!_nexell_hwc_window_can_set_on_hw_layer(composited_list[i])) + goto set_clients_below; + + //lzpos = _nexell_hwc_window_get_lzpos(composited_list[i]); + //if (lzpos == -1) break; + + for (j = ZPOS_2; j >= ZPOS_0; j--) { + if (use_hw_layers[j]) continue; + lzpos = j; + break; + } + /* check no available hw_layer */ + if (lzpos == -1) break; + + /* set clients below when the hwc_window does not have the reserved buffer */ + if (!_nexell_hwc_window_has_reserved_buffer(composited_list[i])) + { + /* set the buffer_queue constraint */ + composited_list[i]->constraints = TDM_HWC_WIN_CONSTRAINT_BUFFER_QUEUE; + composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CLIENT; + composited_list[i]->lzpos = -1; + composited_list[i]->lzpos_queue = lzpos; + hwc_data->need_target_window = 1; + TDM_DBG(" NO reserved_buffer.(%s) Request acquire_buffer_queue(lzpos_queue:%d) for SCANOUT Buffer.", composited_list[i]->name, lzpos); + break; + } + + /* set the constraint_buffer_queue, validated_type, lzpos, lqueue of the UI layer */ + composited_list[i]->constraints = TDM_HWC_WIN_CONSTRAINT_BUFFER_QUEUE; + composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_DEVICE; + composited_list[i]->lzpos = lzpos; + composited_list[i]->lzpos_queue = lzpos; + use_hw_layers[lzpos] = 1; + TDM_DBG("YES reserved_buffer.(%s) Set the DEVICE_TYPE.", composited_list[i]->name); + } + +set_clients_below: + for (i = 0; i < num_wnds; i++) { + if (composited_list[i]->validated_type != TDM_HWC_WIN_COMPOSITION_NONE) + continue; + + composited_list[i]->constraints = TDM_HWC_WIN_CONSTRAINT_NONE; + composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CLIENT; + composited_list[i]->lzpos = -1; + composited_list[i]->lzpos_queue = -1; + + if (!hwc_data->need_target_window) { + hwc_data->need_target_window = 1; + hwc_data->target_hwc_window->lzpos = ZPOS_1; + hwc_data->target_hwc_window->lzpos_queue = ZPOS_1; + } + } +} + +static int +_nexell_hwc_get_changed_number(tdm_nexell_hwc_data *hwc_data) +{ + int num = 0; + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + + LIST_FOR_EACH_ENTRY(hwc_window_data, &hwc_data->hwc_window_list, link) { + if (hwc_window_data->client_type == TDM_HWC_WIN_COMPOSITION_NONE) + continue; + + if (hwc_window_data->client_type != hwc_window_data->validated_type) + num++; + } + + return num; +} + +tdm_hwc_window * +_nexell_hwc_create_window(tdm_hwc *hwc, tdm_hwc_window_info *info, tdm_error *error) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + + if (error) + *error = TDM_ERROR_NONE; + + if (!hwc_data) { + TDM_ERR("invalid params"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + hwc_window_data = calloc(1, sizeof(tdm_nexell_hwc_window_data)); + if (!hwc_window_data) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + hwc_window_data->hwc_data = hwc_data; + + if (info) + memcpy(&hwc_window_data->info, info, sizeof(tdm_hwc_window_info)); + + LIST_INITHEAD(&hwc_window_data->link); + + return hwc_window_data; +} + +tdm_hwc_window * +nexell_hwc_create_window(tdm_hwc *hwc, tdm_error *error) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + + RETURN_VAL_IF_FAIL(hwc_data, NULL); + + hwc_window_data = _nexell_hwc_create_window(hwc_data, NULL, error); + RETURN_VAL_IF_FAIL(hwc_window_data, NULL); + + LIST_ADDTAIL(&hwc_window_data->link, &hwc_data->hwc_window_list); + + TDM_DBG("hwc_window(%p) create", hwc_window_data); + if (error) + *error = TDM_ERROR_NONE; + + return hwc_window_data; +} + +tdm_error +nexell_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count) +{ + RETURN_VAL_IF_FAIL(hwc != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + // TODO: fix these formats. + *formats = hwc_window_video_formats; + *count = sizeof(hwc_window_video_formats) / sizeof(tbm_format); + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities) +{ + RETURN_VAL_IF_FAIL(hwc != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER); + + *capabilities |= 0; + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + *props = NULL; + *count = 0; + + return TDM_ERROR_NONE; +} + +tbm_surface_queue_h +nexell_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tbm_surface_queue_h tqueue = NULL; + + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + + RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL); + + if (hwc_data->target_hwc_window == NULL) { + if (error) + *error = TDM_ERROR_OPERATION_FAILED; + return NULL; + } + + tqueue = tdm_nexell_hwc_window_create_tbm_buffer_queue(hwc_data->target_hwc_window, error); + RETURN_VAL_IF_FAIL(tqueue, NULL); + + if (error) { + *error = TDM_ERROR_NONE; + /* reference the target_buffer queue */ + hwc_data->ui_buffer_queue[ZPOS_1].tqueue = tqueue; + hwc_data->ui_buffer_queue[ZPOS_1].ref_cnt = 1; + + for (int i = NUM_LAYERS-1; i >= 0; i--) { + TDM_ERR("[%d]: lzpos_queue:%d tqueue:%p, ref_cnt:%d", + i, i, + hwc_data->ui_buffer_queue[i].tqueue, + hwc_data->ui_buffer_queue[i].ref_cnt); + } + } + + return tqueue; +} + +tdm_error +nexell_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h buffer, tdm_region damage) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_error err; + + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window != NULL, TDM_ERROR_OPERATION_FAILED); + + err = nexell_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer); + RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err); + + err = nexell_hwc_window_set_buffer_damage(hwc_data->target_hwc_window, damage); + RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err); + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_nexell_output_data *output_data; + + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + RETURN_VAL_IF_FAIL(output_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + TDM_INFO(" ==============Validate================================="); + + /* adapt policy */ + _nexell_hwc_apply_policy(hwc_data, composited_wnds, num_wnds); + + *num_types = _nexell_hwc_get_changed_number(hwc_data); + + _print_validate_result(hwc_data, composited_wnds, num_wnds); + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements, + tdm_hwc_window **hwc_wnds, tdm_hwc_window_composition *composition_types) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + int num = 0; + + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER); + + if ((hwc_wnds == NULL) || (composition_types == NULL)) { + *num_elements = _nexell_hwc_get_changed_number(hwc_data); + return TDM_ERROR_NONE; + } + + LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) { + if (hwc_window_data->client_type == 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 TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_accept_validation(tdm_hwc *hwc) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_error ret = TDM_ERROR_NONE; + + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(hwc_data->output_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + TDM_DBG(" ==============Accept Changes Done================================="); + + ret = _nexell_hwc_prepare_commit(hwc_data); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_commit(tdm_hwc *hwc, int sync, void *user_data) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + tdm_nexell_output_data *output_data = NULL; + tdm_error ret; + + RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER); + + output_data = hwc_data->output_data; + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + TDM_INFO(" ==============COMMIT================================="); + + ret = nexell_output_commit(output_data, sync, user_data); + RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_set_commit_handler(tdm_hwc *hwc, tdm_hwc_commit_handler func) +{ + tdm_nexell_hwc_data *hwc_data = hwc; + + RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + hwc_data->commit_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_target_window_set_info(tdm_nexell_hwc_data *hwc_data, int width, int height) +{ + tdm_hwc_window_info info = {0}; + tdm_nexell_hwc_window_data *target_hwc_window; + tdm_error ret = TDM_ERROR_NONE; + + RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window, TDM_ERROR_INVALID_PARAMETER); + + target_hwc_window = hwc_data->target_hwc_window; + + info.dst_pos.x = 0; + info.dst_pos.y = 0; + info.dst_pos.w = width; + info.dst_pos.h = height; + + info.src_config.pos.x = 0; + info.src_config.pos.y = 0; + info.src_config.pos.w = width; + info.src_config.pos.h = height; + + info.src_config.size.h = width; + info.src_config.size.v = height; + info.src_config.format = TBM_FORMAT_ARGB8888; + + ret = nexell_hwc_window_set_info(target_hwc_window, &info); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("set info target hwc window failed (%d)", ret); + return TDM_ERROR_OPERATION_FAILED; + } + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_initailize_target_window(tdm_nexell_hwc_data *hwc_data) +{ + tdm_hwc_window_info info = {0}; + tdm_error ret = TDM_ERROR_NONE; + tdm_nexell_hwc_window_data *target_hwc_window; + + RETURN_VAL_IF_FAIL(hwc_data, 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 = _nexell_hwc_create_window(hwc_data, &info, &ret); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("create target hwc window failed (%d)", ret); + return TDM_ERROR_OPERATION_FAILED; + } + + if (hwc_data->target_hwc_window) + nexell_hwc_window_destroy(hwc_data->target_hwc_window); + + hwc_data->target_hwc_window = target_hwc_window; + hwc_data->need_set_crtc = 1; + + return TDM_ERROR_NONE; +} diff --git a/src/tdm_nexell_hwc.h b/src/tdm_nexell_hwc.h new file mode 100644 index 0000000..048cb99 --- /dev/null +++ b/src/tdm_nexell_hwc.h @@ -0,0 +1,9 @@ +#ifndef _TDM_NEXELL_HWC_H_ +#define _TDM_NEXELL_HWC_H_ + +#include "tdm_nexell.h" + +tdm_error nexell_hwc_initailize_target_window(tdm_nexell_hwc_data *hwc_data); +tdm_error nexell_hwc_target_window_set_info(tdm_nexell_hwc_data *hwc_data, int width, int height); + +#endif /* _TDM_NEXELL_HWC_H_ */ diff --git a/src/tdm_nexell_hwc_window.c b/src/tdm_nexell_hwc_window.c new file mode 100644 index 0000000..6ab54a9 --- /dev/null +++ b/src/tdm_nexell_hwc_window.c @@ -0,0 +1,227 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_nexell.h" + +tbm_surface_queue_h +nexell_hwc_window_acquire_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error) +{ + tdm_nexell_hwc_data *hwc_data = NULL; + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + tbm_surface_queue_h tqueue = NULL; + + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + + hwc_window_data = (tdm_nexell_hwc_window_data *)hwc_window; + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, NULL); + + hwc_data = hwc_window_data->hwc_data; + RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL); + + if (error) + *error = TDM_ERROR_NONE; + + if (hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue) { + /* reference the ui_buffer queue */ + tqueue = hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue; + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt++; + TDM_ERR(" Acquire BUFFER_QUEUE[reference]: lzpos_queue:%d tqueue:%p ref_cnt:%d", + hwc_window_data->lzpos_queue, + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue, + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt); + } else { + /* create a ui_buffer_queue */ + tqueue = tdm_nexell_hwc_window_create_tbm_buffer_queue(hwc_window_data, error); + RETURN_VAL_IF_FAIL(tqueue != NULL, NULL); + + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue = tqueue; + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt = 1; + TDM_ERR(" Acquire BUFFER_QUEUE[create]: lzpos_queue:%d tqueue:%p ref_cnt:%d", + hwc_window_data->lzpos_queue, + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue, + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt); + } + + return tqueue; +} + +void +nexell_hwc_window_release_buffer_queue(tdm_hwc_window *hwc_window, tbm_surface_queue_h queue) +{ + tdm_nexell_hwc_data *hwc_data = NULL; + tdm_nexell_hwc_window_data *hwc_window_data = NULL; + + hwc_window_data = (tdm_nexell_hwc_window_data *)hwc_window; + RETURN_IF_FAIL(hwc_window_data != NULL); + + hwc_data = hwc_window_data->hwc_data; + RETURN_IF_FAIL(hwc_data != NULL); + + if (hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt > 0) { + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt--; + + TDM_ERR(" Release BUFFER_QUEUE[dereference]: lzpos_queue:%d tqueue:%p ref_cnt:%d", + hwc_window_data->lzpos_queue, + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue, + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt); + + /* destroy a ui_buffer_queue when ref_cnt is 0 */ + if (hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].ref_cnt == 0) { + TDM_ERR(" Release BUFFER_QUEUE", "destroy buffer_queue(%p)", hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue); + + tdm_nexell_hwc_window_destroy_tbm_buffer_queue(hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue); + hwc_data->ui_buffer_queue[hwc_window_data->lzpos_queue].tqueue = NULL; + } + } +} + +void +nexell_hwc_window_destroy(tdm_hwc_window *hwc_window) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_IF_FAIL(hwc_window_data != NULL); + + LIST_DEL(&hwc_window_data->link); + + free(hwc_window_data); +} + +tdm_error +nexell_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, + tdm_hwc_window_composition comp_type) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + tdm_nexell_hwc_data *hwc_data = hwc_window_data->hwc_data; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + /* change the client_type when it is different from one which has before */ + if (hwc_window_data->client_type == comp_type) + return TDM_ERROR_NONE; + + hwc_window_data->client_type = comp_type; + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_region damage) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + //TODO:: + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + tdm_nexell_hwc_data *hwc_data; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + hwc_data = hwc_window_data->hwc_data; + RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (!memcmp(&hwc_window_data->info, info, sizeof(tdm_hwc_window_info))) + return TDM_ERROR_NONE; + + hwc_window_data->info = *info; + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + tdm_error err = TDM_ERROR_OPERATION_FAILED; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, err); + + if (hwc_window_data->surface == surface) + return TDM_ERROR_NONE; + + hwc_window_data->surface = surface; + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_set_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value value) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + //TODO: + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_get_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value *value) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + //TODO: + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_get_constraints(tdm_hwc_window *hwc_window, int *constraints) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(constraints != NULL, TDM_ERROR_INVALID_PARAMETER); + + *constraints = hwc_window_data->constraints; + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_set_name(tdm_hwc_window *hwc_window, const char *name) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + + if (!name) + return TDM_ERROR_NONE; + + snprintf(hwc_window_data->name, TDM_NAME_LEN, "%s", name); + + return TDM_ERROR_NONE; +} + +tdm_error +nexell_hwc_window_set_cursor_image(tdm_hwc_window *hwc_window, int width, int height, int stride, void *ptr) +{ + tdm_nexell_hwc_window_data *hwc_window_data = hwc_window; + + RETURN_VAL_IF_FAIL(hwc_window_data != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(hwc_window_data->client_type == TDM_HWC_WIN_COMPOSITION_CURSOR, TDM_ERROR_INVALID_PARAMETER); + + hwc_window_data->cursor_img.width = width; + hwc_window_data->cursor_img.height = height; + hwc_window_data->cursor_img.stride = stride; + hwc_window_data->cursor_img.ptr = ptr; + + hwc_window_data->cursor_img_refresh = 1; + + return TDM_ERROR_NONE; +} diff --git a/src/tdm_nexell_hwc_window.h b/src/tdm_nexell_hwc_window.h new file mode 100644 index 0000000..e801924 --- /dev/null +++ b/src/tdm_nexell_hwc_window.h @@ -0,0 +1,6 @@ +#ifndef _TDM_NEXELL_HWC_WINDOW_H_ +#define _TDM_NEXELL_HWC_WINDOW_H_ + +#include "tdm_nexell.h" + +#endif /* _TDM_NEXELL_HWC_WINDOW_H_ */ diff --git a/src/tdm_nexell_types.h b/src/tdm_nexell_types.h new file mode 100644 index 0000000..2cba880 --- /dev/null +++ b/src/tdm_nexell_types.h @@ -0,0 +1,258 @@ +#ifndef _TDM_NEXELL_TYPES_H_ +#define _TDM_NEXELL_TYPES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_UDEV +#include +#endif + +#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 IS_RGB(format) (format == TBM_FORMAT_XRGB8888 || format == TBM_FORMAT_ARGB8888 || \ + format == TBM_FORMAT_XBGR8888 || format == TBM_FORMAT_ABGR8888) + +#define CLEAR(x) memset(&(x), 0, sizeof(x)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define SWAP(a, b) ({int t; t = a; a = b; b = t; }) +#define ROUNDUP(x) (ceil(floor((float)(height) / 4))) + +#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4) +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11) +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) +#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define CURSOR_MIN_W 192 +#define CURSOR_MIN_H 192 +#define CURSOR_MAX_W 192 +#define CURSOR_MAX_H 192 + +#define NUM_BUFFERS 3 + +#define NUM_LAYERS 3 +#define NUM_UI_LAYERS 2 +#define ZPOS_MAX 2 +#define ZPOS_CURSOR 2 // cursor +#define ZPOS_2 2 // ui +#define ZPOS_1 1 // ui, primary layer +#define ZPOS_0 0 // video +#define ZPOS_VIDEO1 0 // video +#define ZPOS_NONE -999 + +#define RETURN_VAL_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + return val;\ + } \ +} + +#define RETURN_IF_FAIL(cond) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + return;\ + } \ +} + +#define GOTO_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + goto val;\ + } \ +} + +typedef struct _tdm_nexell_data tdm_nexell_data; +typedef struct _tdm_nexell_output_data tdm_nexell_output_data; +typedef struct _tdm_nexell_layer_data tdm_nexell_layer_data; +typedef struct _tdm_nexell_hwc_data tdm_nexell_hwc_data; +typedef struct _tdm_nexell_hwc_window_data tdm_nexell_hwc_window_data; +typedef struct _tdm_nexell_event_data tdm_nexell_event_data; +typedef struct _tdm_nexell_display_buffer tdm_nexell_display_buffer; + +typedef enum { + TDM_NEXELL_EVENT_TYPE_WAIT, + TDM_NEXELL_EVENT_TYPE_COMMIT, + TDM_NEXELL_EVENT_TYPE_PAGEFLIP, +} tdm_nexell_event_type; + +struct _tdm_nexell_data +{ + tdm_display *dpy; + + int drm_fd; + int scaler_fd; + +#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47 + int has_universal_plane; +#endif + +#if HAVE_UDEV + struct udev_monitor *uevent_monitor; + tdm_event_loop_source *uevent_source; +#endif + + drmModeResPtr mode_res; + drmModePlaneResPtr plane_res; + + int hwc_mode; + + struct list_head output_list; + struct list_head buffer_list; +}; + +struct _tdm_nexell_display_buffer { + struct list_head link; + + unsigned int fb_id; + tbm_surface_h buffer; + int width; + unsigned int height; + unsigned int format; + unsigned int handles[4]; + unsigned int fds[4]; + unsigned int pitches[4]; + unsigned int offsets[4]; + unsigned int size; + unsigned int count; +}; + +struct _tdm_nexell_event_data { + tdm_nexell_event_type type; + tdm_nexell_output_data *output_data; + void *user_data; +}; + +struct _tdm_nexell_output_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_nexell_data *nexell_data; + uint32_t connector_id; + uint32_t encoder_id; + uint32_t crtc_id; + uint32_t pipe; + uint32_t dpms_prop_id; + int count_modes; + drmModeModeInfoPtr drm_modes; + tdm_output_mode *output_modes; + tdm_output_type connector_type; + unsigned int connector_type_id; + struct list_head layer_list; + tdm_nexell_layer_data *primary_layer; + + /* not fixed data below */ + tdm_output_vblank_handler vblank_func; + tdm_output_commit_handler commit_func; + + tdm_output_conn_status status; + tdm_output_status_handler status_func; + void *status_user_data; + + int mode_changed; + const tdm_output_mode *current_mode; + + tbm_surface_h crtc_buffer; + int crtc_enabled; + unsigned int crtc_fb_id; + + /* hwc */ + int hwc_enable; + tdm_nexell_hwc_data *hwc_data; +}; + +struct _tdm_nexell_layer_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_nexell_data *nexell_data; + tdm_nexell_output_data *output_data; + uint32_t plane_id; + tdm_layer_capability capabilities; + int zpos; + + /* not fixed data below */ + tdm_info_layer info; + int info_changed; + + tdm_nexell_display_buffer *display_buffer; + int display_buffer_changed; +}; + +struct _tdm_nexell_hwc_data { + tdm_nexell_hwc_window_data *target_hwc_window; + + int need_validate; + int need_target_window; + int need_set_crtc; + + int target_window_zpos; + + tdm_nexell_output_data *output_data; + struct list_head hwc_window_list; + + tbm_surface_h cursor_tsurface; + + /* UI buffer_queue list for the reserved scanout memory */ + struct { + tbm_surface_queue_h tqueue; + int ref_cnt; + } ui_buffer_queue[NUM_LAYERS]; + + tdm_hwc_commit_handler commit_func; +}; + +struct _tdm_nexell_hwc_window_data { + struct list_head link; + + tdm_nexell_hwc_data *hwc_data; + + tdm_hwc_window_info info; + tbm_surface_h surface; + tdm_hwc_window_composition client_type; + tdm_hwc_window_composition validated_type; + int lzpos; + int lzpos_queue; + + char name[TDM_NAME_LEN]; + struct { + int width; + int height; + int stride; + void *ptr; + } cursor_img; + int cursor_img_surface; + int cursor_img_refresh; + + int constraints; + tbm_surface_queue_h tqueue; +}; + +#endif /* _TDM_NEXELL_TYPES_H_ */ -- 2.7.4