summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSooChan Lim <sc1.lim@samsung.com>2019-09-05 19:56:57 +0900
committerSooChan Lim <sc1.lim@samsung.com>2019-09-06 15:27:06 +0900
commit58ebe2fac9a7d23140a0de2108ac8788b8e92d36 (patch)
tree1e6c84c58f578ff933252e16c9b354678fba1925
parent24488f492ee4a53cff2502e5beab64c388d3b1e9 (diff)
downloadlibtdm-drm-58ebe2fac9a7d23140a0de2108ac8788b8e92d36.tar.gz
libtdm-drm-58ebe2fac9a7d23140a0de2108ac8788b8e92d36.tar.bz2
libtdm-drm-58ebe2fac9a7d23140a0de2108ac8788b8e92d36.zip
implement TDM HWC
Change-Id: Iff72f644f6f22d6f2ae67a765d26d300cb443d7c
-rw-r--r--src/Makefile.am2
-rw-r--r--src/tdm_drm.c51
-rw-r--r--src/tdm_drm.h89
-rw-r--r--src/tdm_drm_display.c206
-rw-r--r--src/tdm_drm_hwc.c761
-rw-r--r--src/tdm_drm_hwc.h9
-rw-r--r--src/tdm_drm_hwc_window.c154
-rw-r--r--src/tdm_drm_hwc_window.h6
-rw-r--r--src/tdm_drm_types.h226
9 files changed, 1365 insertions, 139 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 09338b8..16c3a35 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,8 @@ libtdm_drm_la_LDFLAGS = -module -avoid-version
libtdm_drm_la_LIBADD = $(TDM_DRM_LIBS) -ldl
libtdm_drm_la_SOURCES = \
+ tdm_drm_hwc_window.c \
+ tdm_drm_hwc.c \
tdm_drm_format.c \
tdm_drm_pp.c \
tdm_drm_display.c \
diff --git a/src/tdm_drm.c b/src/tdm_drm.c
index 102c7b8..1c2e968 100644
--- a/src/tdm_drm.c
+++ b/src/tdm_drm.c
@@ -14,6 +14,8 @@
#define TDM_DRM_NAME "vigs"
+#define TDM_HWC 0
+
static tdm_drm_data *drm_data;
#ifdef HAVE_UDEV
@@ -234,6 +236,8 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
tdm_func_display drm_func_display;
tdm_func_output drm_func_output;
tdm_func_layer drm_func_layer;
+ tdm_func_hwc drm_func_hwc;
+ tdm_func_hwc_window drm_func_hwc_window;
#ifdef ENABLE_PP
tdm_func_pp drm_func_pp;
#endif
@@ -261,6 +265,11 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
return NULL;
}
+#if TDM_HWC
+ /* enable the tdm_hwc */
+ drm_data->hwc_mode = 1;
+#endif
+
LIST_INITHEAD(&drm_data->output_list);
LIST_INITHEAD(&drm_data->buffer_list);
@@ -289,6 +298,38 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
drm_func_output.output_set_status_handler = drm_output_set_status_handler;
#endif
+ if (drm_data->hwc_mode) {
+ drm_func_output.output_get_hwc = drm_output_get_hwc;
+
+ memset(&drm_func_hwc, 0, sizeof(drm_func_hwc));
+ drm_func_hwc.hwc_create_window = drm_hwc_create_window;
+ drm_func_hwc.hwc_get_video_supported_formats = drm_hwc_get_video_supported_formats;
+ drm_func_hwc.hwc_get_video_available_properties = NULL;
+ drm_func_hwc.hwc_get_capabilities = drm_hwc_get_capabilities;
+ drm_func_hwc.hwc_get_available_properties = drm_hwc_get_available_properties;
+ drm_func_hwc.hwc_get_client_target_buffer_queue = drm_hwc_get_client_target_buffer_queue;
+ drm_func_hwc.hwc_set_client_target_buffer = drm_hwc_set_client_target_buffer;
+ drm_func_hwc.hwc_validate = drm_hwc_validate;
+ drm_func_hwc.hwc_get_changed_composition_types = drm_hwc_get_changed_composition_types;
+ drm_func_hwc.hwc_accept_validation = drm_hwc_accept_validation;
+ drm_func_hwc.hwc_commit = drm_hwc_commit;
+ drm_func_hwc.hwc_set_commit_handler = drm_hwc_set_commit_handler;
+
+ memset(&drm_func_hwc_window, 0, sizeof(drm_func_hwc_window));
+ drm_func_hwc_window.hwc_window_destroy = drm_hwc_window_destroy;
+ drm_func_hwc_window.hwc_window_acquire_buffer_queue = NULL; // no need
+ drm_func_hwc_window.hwc_window_release_buffer_queue = NULL; // no need
+ drm_func_hwc_window.hwc_window_set_composition_type = drm_hwc_window_set_composition_type;
+ drm_func_hwc_window.hwc_window_set_buffer_damage = drm_hwc_window_set_buffer_damage;
+ drm_func_hwc_window.hwc_window_set_info = drm_hwc_window_set_info;
+ drm_func_hwc_window.hwc_window_set_buffer = drm_hwc_window_set_buffer;
+ drm_func_hwc_window.hwc_window_set_property = drm_hwc_window_set_property;
+ drm_func_hwc_window.hwc_window_get_property = drm_hwc_window_get_property;
+ drm_func_hwc_window.hwc_window_get_constraints = drm_hwc_window_get_constraints;
+ drm_func_hwc_window.hwc_window_set_name = drm_hwc_window_set_name;
+ drm_func_hwc_window.hwc_window_set_cursor_image = drm_hwc_window_set_cursor_image;
+ }
+
memset(&drm_func_layer, 0, sizeof(drm_func_layer));
drm_func_layer.layer_get_capability = drm_layer_get_capability;
drm_func_layer.layer_set_property = drm_layer_set_property;
@@ -319,6 +360,16 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
if (ret != TDM_ERROR_NONE)
goto failed;
+ if (drm_data->hwc_mode) {
+ ret = tdm_backend_register_func_hwc(dpy, &drm_func_hwc);
+ if (ret != TDM_ERROR_NONE)
+ goto failed;
+
+ ret = tdm_backend_register_func_hwc_window(dpy, &drm_func_hwc_window);
+ if (ret != TDM_ERROR_NONE)
+ goto failed;
+ }
+
#ifdef ENABLE_PP
ret = tdm_backend_register_func_pp(dpy, &drm_func_pp);
if (ret != TDM_ERROR_NONE)
diff --git a/src/tdm_drm.h b/src/tdm_drm.h
index 2b6971b..f492723 100644
--- a/src/tdm_drm.h
+++ b/src/tdm_drm.h
@@ -24,6 +24,9 @@
#include <tdm_backend.h>
#include <tdm_log.h>
#include <tdm_list.h>
+#include "tdm_drm_types.h"
+#include "tdm_drm_hwc.h"
+#include "tdm_drm_hwc_window.h"
#if HAVE_UDEV
#include <libudev.h>
@@ -49,6 +52,31 @@ tdm_error drm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value);
tdm_error drm_output_set_mode(tdm_output *output, const tdm_output_mode *mode);
tdm_error drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode);
tdm_error drm_output_set_status_handler(tdm_output *output, tdm_output_status_handler func, void *user_data);
+tdm_hwc *drm_output_get_hwc(tdm_output *output, tdm_error *error);
+
+tdm_hwc_window *drm_hwc_create_window(tdm_hwc *hwc, tdm_error *error);
+tdm_error drm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count);
+tdm_error drm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities);
+tdm_error drm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count);
+tbm_surface_queue_h drm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error);
+tdm_error drm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h buffer, tdm_region damage);
+tdm_error drm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types);
+tdm_error drm_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 drm_hwc_accept_validation(tdm_hwc *hwc);
+tdm_error drm_hwc_commit(tdm_hwc *hwc, int sync, void *user_data);
+tdm_error drm_hwc_set_commit_handler(tdm_hwc *hwc, tdm_hwc_commit_handler func);
+
+void drm_hwc_window_destroy(tdm_hwc_window *hwc_window);
+tdm_error drm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, tdm_hwc_window_composition composition_type);
+tdm_error drm_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_region damage);
+tdm_error drm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info);
+tdm_error drm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface);
+tdm_error drm_hwc_window_set_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value value);
+tdm_error drm_hwc_window_get_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value *value);
+tdm_error drm_hwc_window_get_constraints(tdm_hwc_window *hwc_window, int *constraints);
+tdm_error drm_hwc_window_set_name(tdm_hwc_window *hwc_window, const char *name);
+tdm_error drm_hwc_window_set_cursor_image(tdm_hwc_window *hwc_window, int width, int height, int stride, void *ptr);
+
tdm_error drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
tdm_error drm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value);
tdm_error drm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value);
@@ -62,65 +90,6 @@ tdm_error drm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst);
tdm_error drm_pp_commit(tdm_pp *pp);
tdm_error drm_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_drm_data {
- tdm_display *dpy;
-
- int drm_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_drm_data;
-
uint32_t tdm_drm_format_to_drm_format(tbm_format format);
tbm_format tdm_drm_format_to_tbm_format(uint32_t format);
@@ -129,4 +98,6 @@ tdm_error tdm_drm_display_create_output_list(tdm_drm_data *drm_data);
void tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data);
tdm_error tdm_drm_display_create_layer_list(tdm_drm_data *drm_data);
+tdm_drm_layer_data * drm_output_data_get_layer_data(tdm_drm_output_data *output_data, int layer_zops);
+
#endif /* _TDM_DRM_H_ */
diff --git a/src/tdm_drm_display.c b/src/tdm_drm_display.c
index 7461f2d..4287d8b 100644
--- a/src/tdm_drm_display.c
+++ b/src/tdm_drm_display.c
@@ -11,79 +11,6 @@
static int tdm_drm_buffer_key;
#define TDM_DRM_BUFFER_KEY ((unsigned long)&tdm_drm_buffer_key)
-#define MIN_WIDTH 32
-
-typedef struct _tdm_drm_output_data tdm_drm_output_data;
-typedef struct _tdm_drm_layer_data tdm_drm_layer_data;
-typedef struct _tdm_drm_event_data tdm_drm_event_data;
-
-typedef enum {
- TDM_DRM_EVENT_TYPE_WAIT,
- TDM_DRM_EVENT_TYPE_COMMIT,
- TDM_DRM_EVENT_TYPE_PAGEFLIP,
-} tdm_drm_event_type;
-
-typedef struct _tdm_drm_display_buffer {
- tdm_drm_data *drm_data;
- unsigned int fb_id;
- tbm_surface_h buffer;
- int width;
-} tdm_drm_display_buffer;
-
-struct _tdm_drm_event_data {
- tdm_drm_event_type type;
- tdm_drm_output_data *output_data;
- void *user_data;
-};
-
-struct _tdm_drm_output_data {
- struct list_head link;
-
- /* data which are fixed at initializing */
- tdm_drm_data *drm_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_drm_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_drm_layer_data {
- struct list_head link;
-
- /* data which are fixed at initializing */
- tdm_drm_data *drm_data;
- tdm_drm_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_drm_display_buffer *display_buffer;
- int display_buffer_changed;
-};
-
static void
_tdm_drm_display_buffer_destroy(void *user_data)
{
@@ -402,7 +329,7 @@ _tdm_drm_display_commit_layer(tdm_drm_layer_data *layer_data)
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",
+ TDM_INFO("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,
@@ -420,6 +347,7 @@ _tdm_drm_display_cb_event(int fd, unsigned int sequence,
{
tdm_drm_event_data *event_data = user_data;
tdm_drm_output_data *output_data;
+ tdm_drm_hwc_data *hwc_data;
if (!event_data) {
TDM_ERR("no event data");
@@ -430,9 +358,22 @@ _tdm_drm_display_cb_event(int fd, unsigned int sequence,
switch (event_data->type) {
case TDM_DRM_EVENT_TYPE_PAGEFLIP:
- 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;
+ }
+
+ 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;
case TDM_DRM_EVENT_TYPE_WAIT:
if (output_data->vblank_func)
@@ -440,9 +381,23 @@ _tdm_drm_display_cb_event(int fd, unsigned int sequence,
event_data->user_data);
break;
case TDM_DRM_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;
+ }
+
+ 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;
@@ -752,11 +707,16 @@ void
tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data)
{
tdm_drm_output_data *o = NULL, *oo = NULL;
+ tdm_drm_hwc_data *hwc_data = NULL;
if (LIST_IS_EMPTY(&drm_data->output_list))
return;
LIST_FOR_EACH_ENTRY_SAFE(o, oo, &drm_data->output_list, link) {
+ hwc_data = o->hwc_data;
+ if (hwc_data && hwc_data->target_hwc_window)
+ drm_hwc_window_destroy(hwc_data->target_hwc_window);
+
LIST_DEL(&o->link);
if (!LIST_IS_EMPTY(&o->layer_list)) {
tdm_drm_layer_data *l = NULL, *ll = NULL;
@@ -960,6 +920,9 @@ tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
&output_data->output_modes[j]);
}
+ if (drm_data->hwc_mode)
+ output_data->hwc_enable = 1;
+
LIST_ADDTAIL(&output_data->link, &drm_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)",
@@ -1163,6 +1126,9 @@ drm_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);
@@ -1194,6 +1160,12 @@ drm_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;
@@ -1464,10 +1436,20 @@ tdm_error
drm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
{
tdm_drm_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 = drm_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;
@@ -1487,6 +1469,55 @@ drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
return TDM_ERROR_NONE;
}
+tdm_hwc *
+drm_output_get_hwc(tdm_output *output, tdm_error *error)
+{
+ tdm_drm_hwc_data *hwc_data = NULL;
+ tdm_drm_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_drm_hwc_data));
+ if (!hwc_data) {
+ TDM_ERR("alloc failed");
+ if (error)
+ *error = TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+ hwc_data->output_data = output_data;
+
+ LIST_INITHEAD(&hwc_data->hwc_window_list);
+
+ output_data->hwc_data = hwc_data;
+
+ ret = drm_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
drm_output_set_status_handler(tdm_output *output,
tdm_output_status_handler func,
@@ -1723,3 +1754,18 @@ drm_layer_unset_buffer(tdm_layer *layer)
return TDM_ERROR_NONE;
}
+
+tdm_drm_layer_data *
+drm_output_data_get_layer_data(tdm_drm_output_data *output_data, int layer_zpos)
+{
+ tdm_drm_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;
+}
diff --git a/src/tdm_drm_hwc.c b/src/tdm_drm_hwc.c
new file mode 100644
index 0000000..9e45229
--- /dev/null
+++ b/src/tdm_drm_hwc.c
@@ -0,0 +1,761 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tdm_helper.h>
+#include "tdm_drm.h"
+
+#define MIN_WIDTH 32
+
+#define NUM_LAYERS 4
+#define NUM_BUFFERS 3
+
+#define NUM_UI_LAYERS 2
+
+#define ZPOS_MAX 3
+#define ZPOS_CURSOR 2
+#define ZPOS_1 1
+#define ZPOS_0 0
+#define ZPOS_VIDEO1 0
+#define ZPOS_NONE -999
+
+tbm_format hwc_window_video_formats[] = {
+ TBM_FORMAT_NV12,
+ TBM_FORMAT_YUV420
+};
+
+const char *
+_comp_to_str(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
+_drm_hwc_cursor_buffer_unset(tdm_drm_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
+_drm_hwc_cursor_adjust_pos(tdm_drm_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
+_drm_hwc_cursor_buffer_set(tdm_drm_hwc_data *hwc_data, tdm_drm_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;
+
+ _drm_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_drm_hwc_data *hwc_data, tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+ tdm_drm_hwc_window_data *hwc_window_data = NULL;
+ int i;
+
+ for (i = 0; i < num_wnds; i++) {
+ hwc_window_data = composited_wnds[i];
+ switch (hwc_window_data->validated_type) {
+ case TDM_HWC_WIN_COMPOSITION_CLIENT:
+ TDM_DBG(" window(%p) %s -> %s : lzpos(%d) -- {%s} on TARGET WINDOW", hwc_window_data,
+ _comp_to_str(hwc_window_data->client_type),
+ _comp_to_str(hwc_window_data->validated_type),
+ hwc_data->target_hwc_window->lzpos,
+ hwc_window_data->name ? hwc_window_data->name : "NONE");
+ break;
+ case 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) -- {%s}", hwc_window_data,
+ _comp_to_str(hwc_window_data->client_type),
+ _comp_to_str(hwc_window_data->validated_type),
+ hwc_window_data->lzpos,
+ hwc_window_data->name ? hwc_window_data->name : "NONE");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int
+_drm_hwc_window_can_set_on_hw_layer(tdm_drm_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;
+}
+
+static tbm_surface_queue_h
+_drm_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error)
+{
+ tdm_drm_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;
+}
+
+static tdm_error
+_drm_hwc_layer_attach_window(tdm_drm_layer_data *layer_data, tdm_drm_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 = drm_layer_unset_buffer(layer_data);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ } else {
+ ret = drm_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 = drm_layer_set_buffer(layer_data, hwc_window_data->surface);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ }
+
+ return ret;
+}
+
+static tdm_error
+_drm_hwc_prepare_commit(tdm_drm_hwc_data *hwc_data)
+{
+ tdm_drm_hwc_window_data *hwc_window_data = NULL;
+ tdm_drm_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 = drm_output_data_get_layer_data(hwc_data->output_data, hwc_data->target_hwc_window->lzpos);
+ _drm_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)
+ _drm_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)
+ _drm_hwc_cursor_buffer_set(hwc_data, hwc_window_data);
+
+ layer_data = drm_output_data_get_layer_data(hwc_data->output_data, hwc_window_data->lzpos);
+ _drm_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 = drm_output_data_get_layer_data(hwc_data->output_data, lzpos);
+ if (!layer_data)
+ continue;
+
+ _drm_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
+_drm_hwc_apply_policy(tdm_drm_hwc_data *hwc_data , tdm_hwc_window **composited_wnds, uint32_t num_wnds)
+{
+ tdm_drm_hwc_window_data *hwc_window_data = NULL;
+ tdm_drm_hwc_window_data **composited_list = NULL;
+ int client_count = 0;
+ int device_count = 0;
+ int video_count = 0;
+ int cursor_count = 0;
+ int ui_lzpos_top = ZPOS_1;
+ int ui_lzpos_bottom = ZPOS_0;
+ int num_ui_layers = NUM_UI_LAYERS;
+ int set_clients_below = 0;
+ int i = 0;
+
+ composited_list = (tdm_drm_hwc_window_data **)composited_wnds;
+
+ /* initialize the need_target_window */
+ hwc_data->need_target_window = 0;
+
+ /* initialize the validated_types */
+ LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
+ if (hwc_window_data->validated_type != TDM_HWC_WIN_COMPOSITION_NONE)
+ hwc_window_data->validated_type = TDM_HWC_WIN_COMPOSITION_NONE;
+ }
+
+ /* use the target_window to commit when there is no window. */
+ if (num_wnds == 0) {
+ hwc_data->need_target_window = 1;
+ hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom;
+ return;
+ }
+
+ /* 1. first check validate_type without target_window */
+ for (i = 0; i < num_wnds; i++) {
+ switch (composited_list[i]->client_type) {
+ case TDM_HWC_WIN_COMPOSITION_VIDEO:
+ composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_VIDEO;
+ video_count++;
+ continue;
+ case TDM_HWC_WIN_COMPOSITION_CURSOR:
+ if (set_clients_below) break;
+ if (cursor_count > 0) break;
+
+ composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CURSOR;
+ cursor_count++;
+ continue;
+ case TDM_HWC_WIN_COMPOSITION_DEVICE:
+ if (set_clients_below) break;
+ if (num_ui_layers <= 0) break;
+ if (!_drm_hwc_window_can_set_on_hw_layer(composited_list[i])) break;
+
+ composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_DEVICE;
+ device_count++;
+ num_ui_layers--;
+ continue;
+ default:
+ break;
+ }
+
+ composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CLIENT;
+ client_count++;
+ set_clients_below = 1;
+ }
+
+ /* 2. check need target window and set ui_lzpos top and bottom */
+ num_ui_layers = NUM_UI_LAYERS;
+
+ if (video_count > 0) {
+ ui_lzpos_bottom++;
+ num_ui_layers--;
+ }
+
+ if (client_count > 0) {
+ ui_lzpos_bottom++;
+ num_ui_layers--;
+ hwc_data->need_target_window = 1;
+ hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom - 1;
+ }
+
+ if (num_ui_layers > device_count)
+ ui_lzpos_top = ui_lzpos_bottom + device_count - 1;
+
+ /* 3. set lzpos and modify validate_type with target_window */
+ for (i = 0; i < num_wnds; i++) {
+ switch (composited_list[i]->validated_type) {
+ case TDM_HWC_WIN_COMPOSITION_VIDEO:
+ composited_list[i]->lzpos = ZPOS_VIDEO1;
+ continue;
+ case TDM_HWC_WIN_COMPOSITION_CURSOR:
+ composited_list[i]->lzpos = ZPOS_CURSOR;
+ continue;
+ case TDM_HWC_WIN_COMPOSITION_DEVICE:
+ if (num_ui_layers <= 0) break;
+ composited_list[i]->lzpos = ui_lzpos_top;
+ ui_lzpos_top--;
+ num_ui_layers--;
+ continue;
+ default:
+ break;
+ }
+
+ composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CLIENT;
+ composited_list[i]->lzpos = ZPOS_NONE;
+ }
+}
+
+static int
+_drm_hwc_get_changed_number(tdm_drm_hwc_data *hwc_data)
+{
+ int num = 0;
+ tdm_drm_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 *
+_drm_hwc_create_window(tdm_hwc *hwc, tdm_hwc_window_info *info, tdm_error *error)
+{
+ tdm_drm_hwc_data *hwc_data = hwc;
+ tdm_drm_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_drm_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 *
+drm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
+{
+ tdm_drm_hwc_data *hwc_data = hwc;
+ tdm_drm_hwc_window_data *hwc_window_data = NULL;
+
+ RETURN_VAL_IF_FAIL(hwc_data, NULL);
+
+ hwc_window_data = _drm_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
+drm_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
+drm_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 |= TDM_HWC_CAPABILITY_VIDEO_SCALE;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
+{
+ tdm_drm_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
+drm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
+{
+ tdm_drm_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 = _drm_hwc_window_get_tbm_buffer_queue(hwc_data->target_hwc_window, error);
+ RETURN_VAL_IF_FAIL(tqueue, NULL);
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ return tqueue;
+}
+
+tdm_error
+drm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h buffer, tdm_region damage)
+{
+ tdm_drm_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 = drm_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer);
+ RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
+
+ err = drm_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
+drm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
+{
+ tdm_drm_hwc_data *hwc_data = hwc;
+ tdm_drm_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=================================");
+
+ _drm_hwc_apply_policy(hwc_data, composited_wnds, num_wnds);
+
+ *num_types = _drm_hwc_get_changed_number(hwc_data);
+
+ _print_validate_result(hwc_data, composited_wnds, num_wnds);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
+ tdm_hwc_window **hwc_wnds, tdm_hwc_window_composition *composition_types)
+{
+ tdm_drm_hwc_data *hwc_data = hwc;
+ tdm_drm_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 = _drm_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
+drm_hwc_accept_validation(tdm_hwc *hwc)
+{
+ tdm_drm_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 = _drm_hwc_prepare_commit(hwc_data);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_hwc_commit(tdm_hwc *hwc, int sync, void *user_data)
+{
+ tdm_drm_hwc_data *hwc_data = hwc;
+ tdm_drm_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 = drm_output_commit(output_data, sync, user_data);
+ RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_hwc_set_commit_handler(tdm_hwc *hwc, tdm_hwc_commit_handler func)
+{
+ tdm_drm_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
+drm_hwc_target_window_set_info(tdm_drm_hwc_data *hwc_data, int width, int height)
+{
+ tdm_hwc_window_info info = {0};
+ tdm_drm_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 = drm_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
+drm_hwc_initailize_target_window(tdm_drm_hwc_data *hwc_data)
+{
+ tdm_hwc_window_info info = {0};
+ tdm_error ret = TDM_ERROR_NONE;
+ tdm_drm_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 = _drm_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)
+ drm_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_drm_hwc.h b/src/tdm_drm_hwc.h
new file mode 100644
index 0000000..727110b
--- /dev/null
+++ b/src/tdm_drm_hwc.h
@@ -0,0 +1,9 @@
+#ifndef _TDM_DRM_HWC_H_
+#define _TDM_DRM_HWC_H_
+
+#include "tdm_drm.h"
+
+tdm_error drm_hwc_initailize_target_window(tdm_drm_hwc_data *hwc_data);
+tdm_error drm_hwc_target_window_set_info(tdm_drm_hwc_data *hwc_data, int width, int height);
+
+#endif /* _TDM_DRM_HWC_H_ */
diff --git a/src/tdm_drm_hwc_window.c b/src/tdm_drm_hwc_window.c
new file mode 100644
index 0000000..c005b37
--- /dev/null
+++ b/src/tdm_drm_hwc_window.c
@@ -0,0 +1,154 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tdm_drm.h"
+
+void
+drm_hwc_window_destroy(tdm_hwc_window *hwc_window)
+{
+ tdm_drm_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
+drm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window,
+ tdm_hwc_window_composition comp_type)
+{
+ tdm_drm_hwc_window_data *hwc_window_data = hwc_window;
+ tdm_drm_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
+drm_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_region damage)
+{
+ tdm_drm_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
+drm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info)
+{
+ tdm_drm_hwc_window_data *hwc_window_data = hwc_window;
+ tdm_drm_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
+drm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h surface)
+{
+ tdm_drm_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
+drm_hwc_window_set_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value value)
+{
+ tdm_drm_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
+drm_hwc_window_get_property(tdm_hwc_window *hwc_window, unsigned int id, tdm_value *value)
+{
+ tdm_drm_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
+drm_hwc_window_get_constraints(tdm_hwc_window *hwc_window, int *constraints)
+{
+ tdm_drm_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);
+
+ // no constraints
+ *constraints = 0;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_hwc_window_set_name(tdm_hwc_window *hwc_window, const char *name)
+{
+ tdm_drm_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
+drm_hwc_window_set_cursor_image(tdm_hwc_window *hwc_window, int width, int height, int stride, void *ptr)
+{
+ tdm_drm_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_drm_hwc_window.h b/src/tdm_drm_hwc_window.h
new file mode 100644
index 0000000..265377f
--- /dev/null
+++ b/src/tdm_drm_hwc_window.h
@@ -0,0 +1,6 @@
+#ifndef _TDM_DRM_HWC_WINDOW_H_
+#define _TDM_DRM_HWC_WINDOW_H_
+
+#include "tdm_drm.h"
+
+#endif /* _TDM_DRM_HWC_WINDOW_H_ */ \ No newline at end of file
diff --git a/src/tdm_drm_types.h b/src/tdm_drm_types.h
new file mode 100644
index 0000000..a032742
--- /dev/null
+++ b/src/tdm_drm_types.h
@@ -0,0 +1,226 @@
+#ifndef _TDM_DRM_TYPES_H_
+#define _TDM_DRM_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 MIN_WIDTH 32
+
+/* 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 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 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_drm_data tdm_drm_data;
+typedef struct _tdm_drm_output_data tdm_drm_output_data;
+typedef struct _tdm_drm_layer_data tdm_drm_layer_data;
+typedef struct _tdm_drm_hwc_data tdm_drm_hwc_data;
+typedef struct _tdm_drm_hwc_window_data tdm_drm_hwc_window_data;
+typedef struct _tdm_drm_event_data tdm_drm_event_data;
+typedef struct _tdm_drm_display_buffer tdm_drm_display_buffer;
+
+typedef enum {
+ TDM_DRM_EVENT_TYPE_WAIT,
+ TDM_DRM_EVENT_TYPE_COMMIT,
+ TDM_DRM_EVENT_TYPE_PAGEFLIP,
+} tdm_drm_event_type;
+
+struct _tdm_drm_data {
+ tdm_display *dpy;
+
+ int drm_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_drm_display_buffer {
+ tdm_drm_data *drm_data;
+ unsigned int fb_id;
+ tbm_surface_h buffer;
+ int width;
+};
+
+struct _tdm_drm_event_data {
+ tdm_drm_event_type type;
+ tdm_drm_output_data *output_data;
+ void *user_data;
+};
+
+struct _tdm_drm_output_data {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_drm_data *drm_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_drm_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;
+
+ /* hwc */
+ int hwc_enable;
+ tdm_drm_hwc_data *hwc_data;
+};
+
+struct _tdm_drm_layer_data {
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_drm_data *drm_data;
+ tdm_drm_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_drm_display_buffer *display_buffer;
+ int display_buffer_changed;
+};
+
+struct _tdm_drm_hwc_data {
+ tdm_drm_hwc_window_data *target_hwc_window;
+
+ int need_validate;
+ int need_target_window;
+ int need_set_crtc;
+
+ int target_window_zpos;
+
+ tdm_drm_output_data *output_data;
+ struct list_head hwc_window_list;
+
+ tbm_surface_h cursor_tsurface;
+
+ tdm_hwc_commit_handler commit_func;
+};
+
+struct _tdm_drm_hwc_window_data {
+ struct list_head link;
+
+ tdm_drm_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;
+
+ char name[TDM_NAME_LEN];
+ struct {
+ int width;
+ int height;
+ int stride;
+ void *ptr;
+ } cursor_img;
+ int cursor_img_surface;
+ int cursor_img_refresh;
+};
+
+#endif /* _TDM_DRM_TYPES_H_ */