Implementation of TDM_HWC 29/252229/1
authorSooChan Lim <sc1.lim@samsung.com>
Mon, 21 Dec 2020 10:29:25 +0000 (19:29 +0900)
committerChangyeon Lee <cyeon.lee@samsung.com>
Fri, 22 Jan 2021 07:10:09 +0000 (16:10 +0900)
nexell backend supports TDM_HWC.
libtdm-nexell operates the displaying buffers with TDM_HWC feature.

Change-Id: I6da21f5e21ad71bf7ee21fc2c06b3db738c4bf0f

src/Makefile.am
src/tdm_nexell.c
src/tdm_nexell.h
src/tdm_nexell_display.c
src/tdm_nexell_hwc.c [new file with mode: 0644]
src/tdm_nexell_hwc.h [new file with mode: 0644]
src/tdm_nexell_hwc_window.c [new file with mode: 0644]
src/tdm_nexell_hwc_window.h [new file with mode: 0644]
src/tdm_nexell_types.h [new file with mode: 0644]

index 296b6a1..f026ba8 100644 (file)
@@ -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
index a38e294..23c95d3 100644 (file)
@@ -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
 };
index 119970a..461ea1d 100644 (file)
@@ -24,6 +24,9 @@
 #include <tdm_backend.h>
 #include <tdm_log.h>
 #include <tdm_list.h>
+#include "tdm_nexell_types.h"
+#include "tdm_nexell_hwc.h"
+#include "tdm_nexell_hwc_window.h"
 
 #if HAVE_UDEV
 #include <libudev.h>
@@ -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_ */
index c20a65a..c2c794e 100644 (file)
@@ -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 (file)
index 0000000..d80dedb
--- /dev/null
@@ -0,0 +1,838 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tdm_helper.h>
+#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 (file)
index 0000000..048cb99
--- /dev/null
@@ -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 (file)
index 0000000..6ab54a9
--- /dev/null
@@ -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 (file)
index 0000000..e801924
--- /dev/null
@@ -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 (file)
index 0000000..2cba880
--- /dev/null
@@ -0,0 +1,258 @@
+#ifndef _TDM_NEXELL_TYPES_H_
+#define _TDM_NEXELL_TYPES_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <linux/fb.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <tdm_backend.h>
+#include <tdm_log.h>
+#include <tdm_list.h>
+#include <drm_fourcc.h>
+#include <tdm_helper.h>
+
+#if HAVE_UDEV
+#include <libudev.h>
+#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_ */