diff --git a/COPYING b/LICENSE
similarity index 100%
rename from COPYING
rename to LICENSE
diff --git a/SCR.txt b/SCR.txt
new file mode 100644
index 00000000..dc358eb8
--- /dev/null
+++ b/SCR.txt
@@ -0,0 +1,9 @@
+Package:                     weston-imx.git
+Version:                     12.0.4.imx
+Outgoing License:            MIT
+License File:                COPYING
+Type of Content:             source
+Description and comments:    A reference implementation of a Wayland compositor
+Release Location:            https://github.com/nxp-imx/weston-imx -b lf-6.6.23-2.0.0
+Origin:                      NXP (MIT)
+                             Weston (MIT) - http://github.com/wayland-project/weston/
diff --git a/compositor/config-helpers.c b/compositor/config-helpers.c
index 21a0512e..bd8a6d4e 100644
--- a/compositor/config-helpers.c
+++ b/compositor/config-helpers.c
@@ -70,6 +70,9 @@ struct {
 } renderer_name_map[] = {
 	{ "auto", WESTON_RENDERER_AUTO },
 	{ "gl", WESTON_RENDERER_GL },
+#if defined(ENABLE_IMXG2D)
+	{ "g2d", WESTON_RENDERER_G2D },
+#endif
 	{ "noop", WESTON_RENDERER_NOOP },
 	{ "pixman", WESTON_RENDERER_PIXMAN },
 };
diff --git a/compositor/main.c b/compositor/main.c
index c6144660..ff85ff77 100644
--- a/compositor/main.c
+++ b/compositor/main.c
@@ -719,6 +719,9 @@ usage(int error_code)
 		"  --seat=SEAT\t\tThe seat that weston should run on, instead of the seat defined in XDG_SEAT\n"
 		"  --drm-device=CARD\tThe DRM device to use, e.g. \"card0\".\n"
 		"  --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
+#if defined(ENABLE_IMXG2D)
+		"  --use-g2d\t\tUse the G2D renderer (default: GL rendering)\n"
+#endif
 		"  --current-mode\tPrefer current KMS mode over EDID preferred mode\n"
 		"  --continue-without-input\tAllow the compositor to start without input devices\n\n");
 #endif
@@ -2919,6 +2922,33 @@ load_pipewire(struct weston_compositor *c, struct weston_config *wc)
 	}
 }
 
+static void
+drm_backend_shell_configure(struct weston_compositor *c,
+		struct weston_drm_backend_config *config)
+{
+	struct weston_config_section *section;
+	section = weston_config_get_section(wet_get_config(c),
+					    "shell", NULL, NULL);
+
+	if (section) {
+		char *size;
+		int n;
+		uint32_t width = 0;
+		uint32_t height = 0;
+
+		weston_config_section_get_string(section, "size", &size, NULL);
+
+		if(size){
+			n = sscanf(size, "%dx%d", &width, &height);
+			if (n == 2 && width > 0 && height > 0) {
+				config->shell_width  = width;
+				config->shell_height = height;
+			}
+			free(size);
+		}
+	}
+}
+
 static int
 load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
 		 struct weston_config *wc, enum weston_renderer_type renderer)
@@ -2929,6 +2959,10 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
 	bool without_input = false;
 	bool force_pixman = false;
 	int ret = 0;
+#if defined(ENABLE_IMXG2D)
+	bool use_g2d = false;
+#endif
+	uint32_t enable_overlay_view;
 
 	wet->drm_use_current_mode = false;
 
@@ -2937,12 +2971,20 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
 	weston_config_section_get_bool(section, "use-pixman", &force_pixman,
 				       false);
 
+#if defined(ENABLE_IMXG2D)
+	weston_config_section_get_bool(section, "use-g2d", &config.use_g2d,
+				       use_g2d);
+#endif
+
 	const struct weston_option options[] = {
 		{ WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
 		{ WESTON_OPTION_STRING, "drm-device", 0, &config.specific_device },
 		{ WESTON_OPTION_STRING, "additional-devices", 0, &config.additional_devices},
 		{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode },
 		{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &force_pixman },
+#if defined(ENABLE_IMXG2D)
+		{ WESTON_OPTION_BOOLEAN, "use-g2d", 0, &config.use_g2d },
+#endif
 		{ WESTON_OPTION_BOOLEAN, "continue-without-input", false, &without_input }
 	};
 
@@ -2953,6 +2995,10 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
 		return -1;
 	} else if (force_pixman) {
 		config.renderer = WESTON_RENDERER_PIXMAN;
+#if defined(ENABLE_IMXG2D)
+	}else if (config.use_g2d) {
+		config.renderer = WESTON_RENDERER_G2D;
+#endif
 	} else {
 		config.renderer = renderer;
 	}
@@ -2968,6 +3014,9 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
 	if (without_input)
 		c->require_input = !without_input;
 
+	weston_config_section_get_uint(section, "enable-overlay-view", &enable_overlay_view, 0);
+	config.enable_overlay_view = enable_overlay_view;
+
 	config.base.struct_version = WESTON_DRM_BACKEND_CONFIG_VERSION;
 	config.base.struct_size = sizeof(struct weston_drm_backend_config);
 	config.configure_device = configure_input_device;
@@ -2976,6 +3025,8 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
 	weston_compositor_add_heads_changed_listener(c,
 						&wet->heads_changed_listener);
 
+	drm_backend_shell_configure(c, &config);
+
 	ret = weston_compositor_load_backend(c, WESTON_BACKEND_DRM,
 					     &config.base);
 
@@ -3875,6 +3926,18 @@ sigint_helper(int sig)
 	raise(SIGUSR2);
 }
 
+static void
+wet_set_environment_variables(struct weston_compositor *c)
+{
+	struct weston_config_section *section;
+
+	section = weston_config_get_section(wet_get_config(c),
+					    "environment-variables", NULL, NULL);
+	if (section) {
+		weston_config_set_env(section);
+	}
+}
+
 WL_EXPORT int
 wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
 {
@@ -4098,6 +4161,8 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
 	weston_config_section_get_bool(section, "require-input",
 				       &wet.compositor->require_input, true);
 
+	wet_set_environment_variables(wet.compositor);
+
 	if (load_backend(wet.compositor, backend, &argc, argv, config,
 			 renderer) < 0) {
 		weston_log("fatal: failed to create compositor backend\n");
diff --git a/compositor/screen-share.c b/compositor/screen-share.c
index 9ba64cf7..1c743020 100644
--- a/compositor/screen-share.c
+++ b/compositor/screen-share.c
@@ -827,6 +827,8 @@ shared_output_repainted(struct wl_listener *listener, void *data)
 	pixman_region32_t sb_damage;
 	pixman_region32_t output_damage;
 	pixman_region32_t *global_output_damage;
+	struct weston_config *config;
+	struct weston_config_section *section;
 	struct ss_shm_buffer *sb;
 	int32_t x, y, width, height, stride;
 	int i, nrects, do_yflip, y_orig;
@@ -837,6 +839,13 @@ shared_output_repainted(struct wl_listener *listener, void *data)
 		so->output->compositor->read_format;
 	const pixman_format_code_t pixman_format = read_format->pixman_format;
 
+	bool use_g2d;
+
+	config = wet_get_config(so->output->compositor);
+	section = weston_config_get_section(config, "core", NULL, NULL);
+
+	weston_config_section_get_bool(section, "use-g2d", &use_g2d, false);
+
 	width = so->output->current_mode->width;
 	height = so->output->current_mode->height;
 	stride = width;
@@ -898,7 +907,7 @@ shared_output_repainted(struct wl_listener *listener, void *data)
 		width = r[i].x2 - r[i].x1;
 		height = r[i].y2 - r[i].y1;
 
-		if (do_yflip)
+		if (do_yflip && !use_g2d)
 			y_orig = so->output->current_mode->height - r[i].y2;
 		else
 			y_orig = y;
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index e73852ff..abc151e2 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -2257,8 +2257,7 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
 	if (weston_surface_is_mapped(surface) &&
 	    shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
 
-		if (shsurf->shell->compositor->state == WESTON_COMPOSITOR_ACTIVE &&
-		    shsurf->view->output->power_state == WESTON_OUTPUT_POWER_NORMAL) {
+		if (shsurf->shell->compositor->state == WESTON_COMPOSITOR_ACTIVE) {
 			pixman_region32_fini(&surface->pending.input);
 			pixman_region32_init(&surface->pending.input);
 			pixman_region32_fini(&surface->input);
@@ -2917,6 +2916,37 @@ handle_background_surface_destroy(struct wl_listener *listener, void *data)
 	output->background_surface = NULL;
 }
 
+static void
+desktop_shell_set_surface_size(struct desktop_shell *shell,
+				struct weston_surface *surface)
+{
+	struct weston_config_section *section;
+	if(surface->output &&
+		surface->output->transform == WL_OUTPUT_TRANSFORM_NORMAL) {
+		section = weston_config_get_section(wet_get_config(shell->compositor),
+						    "shell", NULL, NULL);
+		if (section) {
+			char *size;
+			int n;
+			int32_t width, height;
+
+			weston_config_section_get_string(section, "size", &size, NULL);
+
+			if(size){
+				n = sscanf(size, "%dx%d", &width, &height);
+				if (n == 2) {
+					if (surface->output->width > width &&
+						surface->output->height > height) {
+						surface->output->width = width;
+						surface->output->height = height;
+					}
+				}
+				free(size);
+			}
+		}
+	}
+}
+
 static void
 desktop_shell_set_background(struct wl_client *client,
 			     struct wl_resource *resource,
@@ -2946,6 +2976,8 @@ desktop_shell_set_background(struct wl_client *client,
 	surface->output = weston_head_from_resource(output_resource)->output;
 	weston_view_set_output(view, surface->output);
 
+	desktop_shell_set_surface_size(shell, surface);
+
 	sh_output = find_shell_output_from_weston_output(shell, surface->output);
 	if (sh_output->background_surface) {
 		/* The output already has a background, tell our helper
@@ -2986,22 +3018,16 @@ panel_committed(struct weston_surface *es,
 
 	view = container_of(es->views.next, struct weston_view, surface_link);
 
-	/* XXX delete me eventually - it would be better if we didn't get here
-	 * with a dirty transform at all, but for now just make sure the
-	 * transform is updated here. */
-	weston_view_update_transform(view);
-
-	get_panel_size(shell, view, &width, &height);
 	switch (shell->panel_position) {
 	case WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP:
 		break;
 	case WESTON_DESKTOP_SHELL_PANEL_POSITION_BOTTOM:
-		y = view->output->height - height;
+		y = view->output->height - es->height;
 		break;
 	case WESTON_DESKTOP_SHELL_PANEL_POSITION_LEFT:
 		break;
 	case WESTON_DESKTOP_SHELL_PANEL_POSITION_RIGHT:
-		x = view->output->width - width;
+		x = view->output->width - es->width;
 		break;
 	}
 
@@ -3049,6 +3075,8 @@ desktop_shell_set_panel(struct wl_client *client,
 	surface->output = weston_head_from_resource(output_resource)->output;
 	weston_view_set_output(view, surface->output);
 
+	desktop_shell_set_surface_size(shell, surface);
+
 	sh_output = find_shell_output_from_weston_output(shell, surface->output);
 	if (sh_output->panel_surface) {
 		/* The output already has a panel, tell our helper
diff --git a/include/libweston/backend-drm.h b/include/libweston/backend-drm.h
index d47955c7..881db4fe 100644
--- a/include/libweston/backend-drm.h
+++ b/include/libweston/backend-drm.h
@@ -204,6 +204,13 @@ struct weston_drm_backend_config {
 	/** Select the renderer type to use */
 	enum weston_renderer_type renderer;
 
+#if defined(ENABLE_IMXG2D)
+	/** Whether to use the g2d renderer instead of the OpenGL ES renderer. */
+	bool use_g2d;
+#endif
+
+	bool enable_overlay_view;
+
 	/** The seat to be used for input and output.
 	 *
 	 * If seat_id is NULL, the seat is taken from XDG_SEAT environment
@@ -218,6 +225,7 @@ struct weston_drm_backend_config {
 	 * Valid values are:
 	 * - NULL - The default format ("xrgb8888") will be used;
 	 * - "xrgb8888";
+	 * - "argb8888"
 	 * - "rgb565"
 	 * - "xrgb2101010"
 	 * The backend will take ownership of the format pointer and will free
@@ -258,6 +266,10 @@ struct weston_drm_backend_config {
 	 * rendering device.
 	 */
 	char *additional_devices;
+
+	/** Desktop shell size */
+	uint32_t shell_width;
+	uint32_t shell_height;
 };
 
 #ifdef  __cplusplus
diff --git a/include/libweston/config-parser.h b/include/libweston/config-parser.h
index 8ed14a3b..d1cebad2 100644
--- a/include/libweston/config-parser.h
+++ b/include/libweston/config-parser.h
@@ -88,6 +88,9 @@ weston_config_section_get_bool(struct weston_config_section *section,
 const char *
 weston_config_get_name_from_env(void);
 
+void
+weston_config_set_env(struct weston_config_section *section);
+
 struct weston_config *
 weston_config_parse_fp(FILE *file);
 
diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h
index 81873027..d8027273 100644
--- a/include/libweston/libweston.h
+++ b/include/libweston/libweston.h
@@ -2264,6 +2264,9 @@ enum weston_renderer_type {
 	WESTON_RENDERER_NOOP = 1,
 	WESTON_RENDERER_PIXMAN = 2,
 	WESTON_RENDERER_GL = 3,
+#if defined(ENABLE_IMXG2D)
+	WESTON_RENDERER_G2D = 4,
+#endif
 };
 
 int
diff --git a/libweston/backend-drm/drm-gbm.c b/libweston/backend-drm/drm-gbm.c
index e399b329..2eaee0e9 100644
--- a/libweston/backend-drm/drm-gbm.c
+++ b/libweston/backend-drm/drm-gbm.c
@@ -304,6 +304,8 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
 	struct drm_device *device = output->device;
 	struct gbm_bo *bo;
 	struct drm_fb *ret;
+	struct weston_paint_node *pnode;
+	bool have_through_hole = false;
 
 	output->base.compositor->renderer->repaint_output(&output->base,
 							  damage, NULL);
@@ -315,8 +317,17 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
 		return NULL;
 	}
 
-	/* The renderer always produces an opaque image. */
-	ret = drm_fb_get_from_bo(bo, device, true, BUFFER_GBM_SURFACE);
+	/* If there are through holes on the primary plane, the renderer needs to
+	 * produces a non-opaque image, otherwise an opaque image. */
+	wl_list_for_each_reverse(pnode, &output->base.paint_node_z_order_list,
+	                         z_order_link) {
+		if (pnode->need_through_hole) {
+			have_through_hole = true;
+			break;
+		}
+	}
+
+	ret = drm_fb_get_from_bo(bo, device, !have_through_hole, BUFFER_GBM_SURFACE);
 	if (!ret) {
 		weston_log("failed to get drm_fb for bo\n");
 		gbm_surface_release_buffer(output->gbm_surface, bo);
@@ -326,3 +337,165 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
 
 	return ret;
 }
+
+#if defined(ENABLE_IMXG2D)
+static int
+drm_backend_create_g2d_renderer(struct drm_backend *b)
+{
+	if (b->g2d_renderer->drm_display_create(b->compositor,
+					(void *)b->gbm) < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+init_g2d(struct drm_backend *b)
+{
+	b->g2d_renderer = weston_load_module("g2d-renderer.so",
+						 "g2d_renderer_interface",
+						 LIBWESTON_MODULEDIR);
+	if (!b->g2d_renderer) {
+		weston_log("Could not load g2d renderer\n");
+		return -1;
+	}
+
+	struct drm_device *device = b->drm;
+
+	b->gbm = gbm_create_device(device->drm.fd);
+	if (!b->gbm)
+		return -1;
+
+	if (drm_backend_create_g2d_renderer(b) < 0) {
+		gbm_device_destroy(b->gbm);
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+drm_output_init_g2d(struct drm_output *output, struct drm_backend *b)
+{
+	const struct weston_mode *mode = output->base.current_mode;
+	int w = output->base.current_mode->width;
+	int h = output->base.current_mode->height;
+	uint32_t format = output->format->format;
+	enum g2d_format g2dFormat;
+	uint32_t i = 0;
+	struct drm_device *device = b->drm;
+
+	switch (format) {
+		case DRM_FORMAT_XRGB8888:
+			g2dFormat = G2D_BGRX8888;
+			break;
+		case DRM_FORMAT_ARGB8888:
+			g2dFormat = G2D_BGRA8888;
+			break;
+		case DRM_FORMAT_RGB565:
+			g2dFormat = G2D_RGB565;
+			break;
+		default:
+			weston_log("Unsupported pixman format 0x%x\n", format);
+			return -1;
+	}
+
+	struct g2d_renderer_output_options options = {
+		.formats = output->format,
+		.formats_count = 1,
+		.area.x = 0,
+		.area.y = 0,
+		.area.width = mode->width,
+		.area.height = mode->height,
+		.fb_size.width = mode->width,
+		.fb_size.height = mode->height,
+	};
+
+	for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+		struct g2d_surfaceEx* g2dSurface = &(output->g2d_image[i]);
+		int ret;
+		output->dumb[i] = drm_fb_create_dumb(device, w, h, format);
+		if (!output->dumb[i])
+			goto err;
+
+		ret = drmPrimeHandleToFD(device->drm.fd, output->dumb[i]->handles[0], DRM_CLOEXEC,
+				       &output->dumb_dmafd[i]);
+		if(ret < 0)
+			goto err;
+
+		ret = b->g2d_renderer->create_g2d_image(g2dSurface, g2dFormat,
+						output->dumb[i]->map,
+						w, h,
+						output->dumb[i]->strides[0],
+						output->dumb[i]->size,
+						output->dumb_dmafd[i]);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (b->g2d_renderer->drm_output_create(&output->base, &options) < 0)
+		goto err;
+
+	drm_output_init_cursor_egl(output, b);
+
+	return 0;
+
+err:
+	weston_log("drm_output_init_g2d failed.\n");
+	for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+		if (output->dumb[i])
+			drm_fb_unref(output->dumb[i]);
+
+		output->dumb[i] = NULL;
+	}
+
+	return -1;
+}
+
+void
+drm_output_fini_g2d(struct drm_output *output)
+{
+	unsigned int i;
+	struct drm_backend *b = to_drm_backend(output->base.compositor);
+
+	pixman_region32_fini(&output->previous_damage);
+
+	for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+		drm_fb_unref(output->dumb[i]);
+		output->dumb[i] = NULL;
+		close(output->dumb_dmafd[i]);
+	}
+	b->g2d_renderer->output_destroy(&output->base);
+}
+
+struct drm_fb *
+drm_output_render_g2d(struct drm_output_state *state, pixman_region32_t *damage)
+{
+	struct drm_output *output = state->output;
+	struct weston_compositor *ec = output->base.compositor;
+	struct drm_backend *b = to_drm_backend(output->base.compositor);
+	pixman_region32_t total_damage, previous_damage;
+
+	pixman_region32_init(&total_damage);
+	pixman_region32_init(&previous_damage);
+
+	pixman_region32_copy(&previous_damage, damage);
+
+	pixman_region32_union(&total_damage, damage, &output->previous_damage);
+	pixman_region32_copy(&output->previous_damage, &previous_damage);
+
+	output->current_image = (output->current_image + 1) % ARRAY_LENGTH(output->dumb);
+
+	b->g2d_renderer->output_set_buffer(&output->base,
+					  &output->g2d_image[output->current_image]);
+
+	ec->renderer->repaint_output(&output->base, &total_damage, NULL);
+
+	pixman_region32_fini(&total_damage);
+	pixman_region32_fini(&previous_damage);
+
+	return drm_fb_ref(output->dumb[output->current_image]);
+}
+
+#endif
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
index 427ac958..7b274afb 100644
--- a/libweston/backend-drm/drm-internal.h
+++ b/libweston/backend-drm/drm-internal.h
@@ -42,6 +42,10 @@
 #include <sys/mman.h>
 #include <time.h>
 
+#if defined(ENABLE_IMXG2D)
+#include <g2dExt.h>
+#include "renderer-g2d/g2d-renderer.h"
+#endif
 
 #include <xf86drm.h>
 #include <xf86drmMode.h>
@@ -77,6 +81,8 @@
 #define DRM_PLANE_ALPHA_OPAQUE	0xffffUL
 #endif
 
+#define ALIGNTO(a, b) ((a + (b-1)) & (~(b-1)))
+
 /**
  * A small wrapper to print information into the 'drm-backend' debug scope.
  *
@@ -169,6 +175,7 @@ enum wdrm_plane_property {
 	WDRM_PLANE_ZPOS,
 	WDRM_PLANE_ROTATION,
 	WDRM_PLANE_ALPHA,
+	WDRM_PLANE_DTRC_META,
 	WDRM_PLANE__COUNT
 };
 
@@ -340,6 +347,10 @@ struct drm_device {
 
 	bool fb_modifiers;
 
+	/* hdr10 metadata blob id */
+	unsigned int hdr_blob_id;
+	bool clean_hdr_blob;
+
 	/* we need these parameters in order to not fail drmModeAddFB2()
 	 * due to out of bounds dimensions, and then mistakenly set
 	 * sprites_are_broken:
@@ -368,8 +379,17 @@ struct drm_backend {
 	struct wl_listener session_listener;
 	const struct pixel_format_info *format;
 
+#if defined(ENABLE_IMXG2D)
+	bool use_g2d;
+	struct g2d_renderer_interface *g2d_renderer;;
+#endif
+
 	bool use_pixman_shadow;
 
+	bool enable_overlay_view;
+	uint32_t shell_width;
+	uint32_t shell_height;
+
 	struct udev_input input;
 
 	uint32_t pageflip_timeout;
@@ -377,6 +397,8 @@ struct drm_backend {
 	bool shutting_down;
 
 	struct weston_log_scope *debug;
+
+	struct weston_drm_format_array supported_formats;
 };
 
 struct drm_mode {
@@ -419,6 +441,8 @@ struct drm_fb {
 
 	/* Used by dumb fbs */
 	void *map;
+
+	uint64_t dtrc_meta;
 };
 
 struct drm_buffer_fb {
@@ -533,6 +557,8 @@ struct drm_plane {
 
 	struct drm_property_info props[WDRM_PLANE__COUNT];
 
+	uint64_t dtrc_meta;
+
 	/* The last state submitted to the kernel for this plane. */
 	struct drm_plane_state *state_cur;
 
@@ -681,9 +707,14 @@ struct drm_output {
 	/* only set when a writeback screenshot is ongoing */
 	struct drm_writeback_state *wb_state;
 
-	struct drm_fb *dumb[2];
-	struct weston_renderbuffer *renderbuffer[2];
+	struct drm_fb *dumb[3];
+	struct weston_renderbuffer *renderbuffer[3];
+#if defined(ENABLE_IMXG2D)
+	struct g2d_surfaceEx g2d_image[3];
+	int dumb_dmafd[3];
+#endif
 	int current_image;
+	pixman_region32_t previous_damage;
 
 	struct vaapi_recorder *recorder;
 	struct wl_listener recorder_frame_listener;
@@ -696,6 +727,8 @@ struct drm_output {
 	submit_frame_cb virtual_submit_frame;
 
 	enum wdrm_content_type content_type;
+
+	int (*surface_get_in_fence_fd)(struct gbm_surface *surface);
 };
 
 void
@@ -988,6 +1021,22 @@ drm_output_fini_egl(struct drm_output *output);
 
 struct drm_fb *
 drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage);
+#if defined(ENABLE_IMXG2D)
+int
+init_g2d(struct drm_backend *b);
+
+int
+drm_output_init_g2d(struct drm_output *output, struct drm_backend *b);
+
+void
+drm_output_fini_g2d(struct drm_output *output);
+
+struct drm_fb *
+drm_output_render_g2d(struct drm_output_state *state, pixman_region32_t *damage);
+#endif
+
+int
+drm_fb_get_gbm_alignment(struct drm_fb *fb);
 
 #else
 inline static int
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
index 380dd855..1765fbe5 100644
--- a/libweston/backend-drm/drm.c
+++ b/libweston/backend-drm/drm.c
@@ -51,6 +51,8 @@
 #include <libweston/libweston.h>
 #include <libweston/backend-drm.h>
 #include <libweston/weston-log.h>
+#include <libweston/config-parser.h>
+#include "compositor/weston.h"
 #include "drm-internal.h"
 #include "shared/hash.h"
 #include "shared/helpers.h"
@@ -68,6 +70,7 @@
 #include "linux-dmabuf.h"
 #include "linux-dmabuf-unstable-v1-server-protocol.h"
 #include "linux-explicit-synchronization.h"
+#include "hdr10-metadata-unstable-v1-server-protocol.h"
 
 static const char default_seat[] = "seat0";
 
@@ -386,7 +389,10 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
 	struct drm_plane *scanout_plane = output->scanout_plane;
 	struct drm_property_info *damage_info =
 		&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
+	struct drm_backend *b = device->backend;
 	struct drm_fb *fb;
+	uint32_t width;
+	uint32_t height;
 	pixman_region32_t scanout_damage;
 	pixman_box32_t *rects;
 	int n_rects;
@@ -404,16 +410,38 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
 	 * area. But, we still have to call the renderer anyway if any screen
 	 * capture is pending, otherwise the capture will not complete.
 	 */
+
+#ifdef HAVE_GBM_MODIFIERS
+	int gbm_aligned = drm_fb_get_gbm_alignment (scanout_plane->state_cur->fb);
+#endif
+
 	if (!pixman_region32_not_empty(damage) &&
 	    wl_list_empty(&output->base.frame_signal.listener_list) &&
 	    !weston_output_has_renderer_capture_tasks(&output->base) &&
 	    scanout_plane->state_cur->fb &&
 	    (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
-	     scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
+	     scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
+#ifdef HAVE_GBM_MODIFIERS
+	    scanout_plane->state_cur->fb->width ==
+		ALIGNTO(output->base.current_mode->width, gbm_aligned) &&
+	    scanout_plane->state_cur->fb->height ==
+		ALIGNTO(output->base.current_mode->height, gbm_aligned)) {
+#else
+	    scanout_plane->state_cur->fb->width ==
+		output->base.current_mode->width &&
+	    scanout_plane->state_cur->fb->height ==
+		output->base.current_mode->height) {
+#endif
 		fb = drm_fb_ref(scanout_plane->state_cur->fb);
 	} else if (c->renderer->type == WESTON_RENDERER_PIXMAN) {
 		fb = drm_output_render_pixman(state, damage);
-	} else {
+	}
+#if defined(ENABLE_IMXG2D)
+	else if (b->use_g2d) {
+		fb = drm_output_render_g2d(state, damage);
+	}
+#endif
+	else {
 		fb = drm_output_render_gl(state, damage);
 	}
 
@@ -427,13 +455,23 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
 
 	scanout_state->src_x = 0;
 	scanout_state->src_y = 0;
-	scanout_state->src_w = fb->width << 16;
-	scanout_state->src_h = fb->height << 16;
+	scanout_state->src_w = output->base.current_mode->width << 16;
+	scanout_state->src_h = output->base.current_mode->height << 16;
 
 	scanout_state->dest_x = 0;
 	scanout_state->dest_y = 0;
-	scanout_state->dest_w = output->base.current_mode->width;
-	scanout_state->dest_h = output->base.current_mode->height;
+	scanout_state->dest_w = scanout_state->src_w >> 16;
+	scanout_state->dest_h = scanout_state->src_h >> 16;
+	if ( output->base.transform == WL_OUTPUT_TRANSFORM_NORMAL &&
+		b->shell_width > 0 &&
+		b->shell_height > 0) {
+		width = b->shell_width << 16;
+		height = b->shell_height << 16;
+		if (scanout_state->src_w > width && scanout_state->src_h > width){
+			scanout_state->src_w = width;
+			scanout_state->src_h = height;
+		}
+	}
 
 	scanout_state->zpos = scanout_plane->zpos_min;
 
@@ -968,6 +1006,15 @@ drm_output_apply_mode(struct drm_output *output)
 				   "new mode\n");
 			return -1;
 		}
+#if defined(ENABLE_IMXG2D)
+	} else if (b->use_g2d) {
+		drm_output_fini_g2d(output);
+		if (drm_output_init_g2d(output, b) < 0) {
+			weston_log("failed to init output g2d state with "
+				   "new mode\n");
+			return -1;
+		}
+#endif
 	} else {
 		drm_output_fini_egl(output);
 		if (drm_output_init_egl(output, b) < 0) {
@@ -1604,6 +1651,10 @@ parse_gbm_format(const char *s, const struct pixel_format_info *default_format,
 	if (s == NULL) {
 		*format = default_format;
 
+		return 0;
+	}else if (strcmp(s, "argb8888") == 0) {
+		*format = pixel_format_get_info(DRM_FORMAT_ARGB8888);
+
 		return 0;
 	}
 
@@ -2153,6 +2204,13 @@ drm_output_enable(struct weston_output *base)
 			weston_log("Failed to init output pixman state\n");
 			goto err_planes;
 		}
+#if defined(ENABLE_IMXG2D)
+	} else if (b->use_g2d) {
+		if (drm_output_init_g2d(output, b) < 0) {
+			weston_log("Failed to init output g2d state\n");
+			goto err_planes;
+		}
+#endif
 	} else if (drm_output_init_egl(output, b) < 0) {
 		weston_log("Failed to init output gl state\n");
 		goto err_planes;
@@ -2202,6 +2260,10 @@ drm_output_deinit(struct weston_output *base)
 
 	if (b->compositor->renderer->type == WESTON_RENDERER_PIXMAN)
 		drm_output_fini_pixman(output);
+#if defined(ENABLE_IMXG2D)
+	else if (b->use_g2d)
+		drm_output_fini_g2d(output);
+#endif
 	else
 		drm_output_fini_egl(output);
 
@@ -2629,6 +2691,7 @@ drm_output_create(struct weston_backend *backend, const char *name)
 	output->max_bpc = 16;
 #ifdef BUILD_DRM_GBM
 	output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
+	output->surface_get_in_fence_fd = weston_load_module("libgbm.so", "gbm_surface_get_in_fence_fd", LIBDIR);
 #endif
 
 	weston_output_init(&output->base, b->compositor, name);
@@ -3211,6 +3274,8 @@ drm_destroy(struct weston_backend *backend)
 			drm_head_destroy(base);
 	}
 
+	weston_drm_format_array_fini(&b->supported_formats);
+
 	wl_list_for_each_safe(writeback, writeback_tmp,
 			      &b->drm->writeback_connector_list, link)
 		drm_writeback_destroy(writeback);
@@ -3226,6 +3291,16 @@ drm_destroy(struct weston_backend *backend)
 	weston_launcher_close(ec->launcher, device->drm.fd);
 	weston_launcher_destroy(ec->launcher);
 
+	if(b->enable_overlay_view){
+		/* remove enable-overlay-view */
+		char *dir, *path;
+		dir = getenv("XDG_RUNTIME_DIR");
+		path = malloc(strlen(dir) + 40);
+		strcpy(path, dir);
+		strcat(path, "/enable-overlay-view");
+		remove(path);
+		free(path);
+	}
 	free(device->drm.filename);
 	free(device);
 	free(b);
@@ -3293,6 +3368,35 @@ drm_device_changed(struct weston_backend *backend,
 	wl_signal_emit(&compositor->session_signal, compositor);
 }
 
+static const struct weston_drm_format_array *
+drm_get_supported_formats(struct weston_compositor *ec)
+{
+	struct drm_backend *b = to_drm_backend(ec);
+
+	return &b->supported_formats;
+}
+
+/* for drm backend, currently we only need expose overlay plane formats,
+ * because primary will been used by renderer */
+static int
+populate_supported_formats(struct drm_backend *b)
+{
+	int ret = 0;
+	struct drm_plane *plane;
+
+	wl_list_for_each(plane, &b->drm->plane_list, link) {
+		if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
+			continue;
+
+		ret = weston_drm_format_array_join(&b->supported_formats,
+						   &plane->formats);
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
 /**
  * Determines whether or not a device is capable of modesetting. If successful,
  * sets b->drm.fd and b->drm.filename to the opened device.
@@ -3697,6 +3801,144 @@ static const struct weston_drm_output_api api = {
 	drm_output_set_content_type,
 };
 
+/**
+ * Test if drm driver can import dmabuf
+ *
+ * called by compositor when a dmabuf comes to test if this buffer
+ * can used by drm driver directly
+ */
+static bool
+drm_import_dmabuf(struct weston_compositor *compositor,
+	struct linux_dmabuf_buffer *dmabuf)
+{
+	struct drm_backend *b = to_drm_backend(compositor);
+	struct drm_plane *p;
+	uint64_t has_prime;
+	int ret;
+
+	ret = drmGetCap (b->drm->drm.fd, DRM_CAP_PRIME, &has_prime);
+	if (ret || !(bool) (has_prime & DRM_PRIME_CAP_IMPORT)) {
+	        weston_log("drm backend not support import DMABUF\n");
+	        return false;
+	}
+
+	wl_list_for_each(p, &b->drm->plane_list, link) {
+		if (p->type != WDRM_PLANE_TYPE_OVERLAY)
+			continue;
+		struct weston_drm_format * format =
+#if USE_DRM_FORMAT_NV15
+			weston_drm_format_array_find_format (&p->formats, DRM_FORMAT_NV15);
+#else
+			weston_drm_format_array_find_format (&p->formats, DRM_FORMAT_NV12_10LE40);
+#endif
+
+#if USE_DRM_FORMAT_NV15
+		if (format && dmabuf->attributes.format == DRM_FORMAT_NV15)
+#else
+		if (format && dmabuf->attributes.format == DRM_FORMAT_NV12_10LE40)
+#endif
+			return true;
+	}
+
+	return false;
+}
+
+static void
+hdr10_metadata_destroy(struct wl_client *client,
+			  struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static void
+hdr10_metadata_set_metadata(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t eotf,
+				 uint32_t type,
+			     uint32_t display_primaries_red,
+			     uint32_t display_primaries_green,
+			     uint32_t display_primaries_blue,
+			     uint32_t white_point,
+			     uint32_t mastering_display_luminance,
+			     uint32_t max_cll,
+				 uint32_t max_fall)
+{
+	struct weston_compositor *compositor = wl_resource_get_user_data(resource);
+	struct drm_backend *b = to_drm_backend(compositor);
+	struct hdr_output_metadata hdr_metadata;
+
+	if (eotf == 0) {
+		b->drm->clean_hdr_blob = true;
+		return;
+	}
+
+	hdr_metadata.metadata_type = 0;
+	hdr_metadata.hdmi_metadata_type1.eotf = eotf & 0xff;
+	hdr_metadata.hdmi_metadata_type1.metadata_type = type & 0xff;
+	hdr_metadata.hdmi_metadata_type1.display_primaries[0].x = (display_primaries_red >> 16) & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.display_primaries[0].y = display_primaries_red & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.display_primaries[1].x = (display_primaries_green >> 16) & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.display_primaries[1].y = display_primaries_green & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.display_primaries[2].x = (display_primaries_blue >> 16) & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.display_primaries[2].y = display_primaries_blue & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.white_point.x = (white_point >> 16) & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.white_point.y = white_point & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.max_display_mastering_luminance =
+				(mastering_display_luminance >> 16) & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.min_display_mastering_luminance =
+				mastering_display_luminance & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.max_cll = max_cll & 0xffff;
+	hdr_metadata.hdmi_metadata_type1.max_fall = max_fall & 0xffff;
+
+	drmModeCreatePropertyBlob(b->drm->drm.fd, &hdr_metadata, sizeof(hdr_metadata), &b->drm->hdr_blob_id);
+}
+
+static const struct zwp_hdr10_metadata_v1_interface hdr10_metadata_interface = {
+	hdr10_metadata_destroy,
+	hdr10_metadata_set_metadata,
+};
+
+static void
+bind_hdr10_metadata(struct wl_client *client,
+		       void *data, uint32_t version, uint32_t id)
+{
+	struct wl_resource *resource;
+	struct weston_compositor *compositor = data;
+
+	resource = wl_resource_create(client, &zwp_hdr10_metadata_v1_interface,
+				      version, id);
+	if (resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(resource, &hdr10_metadata_interface,
+				       compositor, NULL);
+}
+
+static bool
+drm_backend_is_hdr_supported(struct weston_compositor *compositor)
+{
+	struct drm_output *output;
+	struct drm_head *head;
+
+	wl_list_for_each(output, &compositor->output_list, base.link) {
+		wl_list_for_each(head, &output->base.head_list, base.output_link) {
+			if (head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA].prop_id > 0)
+				return true;
+		}
+	}
+
+	wl_list_for_each(output, &compositor->pending_output_list, base.link) {
+		wl_list_for_each(head, &output->base.head_list, base.output_link) {
+			if (head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA].prop_id > 0)
+				return true;
+		}
+	}
+
+	return true;
+}
+
 static struct drm_backend *
 drm_backend_create(struct weston_compositor *compositor,
 		   struct weston_drm_backend_config *config)
@@ -3728,6 +3970,7 @@ drm_backend_create(struct weston_compositor *compositor,
 	if (device == NULL)
 		return NULL;
 	device->state_invalid = true;
+	device->clean_hdr_blob = false;
 	device->drm.fd = -1;
 	device->backend = b;
 
@@ -3735,6 +3978,12 @@ drm_backend_create(struct weston_compositor *compositor,
 	wl_list_init(&b->kms_list);
 
 	b->compositor = compositor;
+#if defined(ENABLE_IMXG2D)
+	b->use_g2d = config->use_g2d;
+#endif
+	b->enable_overlay_view = config->enable_overlay_view;
+	b->shell_width = config->shell_width;
+	b->shell_height = config->shell_height;
 	b->pageflip_timeout = config->pageflip_timeout;
 	b->use_pixman_shadow = config->use_pixman_shadow;
 
@@ -3789,6 +4038,10 @@ drm_backend_create(struct weston_compositor *compositor,
 		config->renderer = WESTON_RENDERER_GL;
 #else
 		config->renderer = WESTON_RENDERER_PIXMAN;
+#endif
+#if defined(ENABLE_IMXG2D)
+	if (b->use_g2d)
+		config->renderer = WESTON_RENDERER_G2D;
 #endif
 	}
 
@@ -3805,6 +4058,14 @@ drm_backend_create(struct weston_compositor *compositor,
 			goto err_udev_dev;
 		}
 		break;
+#if defined(ENABLE_IMXG2D)
+	case WESTON_RENDERER_G2D:
+		if (init_g2d(b) < 0) {
+			weston_log("failed to initialize g2d renderer\n");
+			goto err_udev_dev;
+		}
+		break;
+#endif
 	default:
 		weston_log("unsupported renderer for DRM backend\n");
 		goto err_udev_dev;
@@ -3817,6 +4078,10 @@ drm_backend_create(struct weston_compositor *compositor,
 	b->base.create_output = drm_output_create;
 	b->base.device_changed = drm_device_changed;
 	b->base.can_scanout_dmabuf = drm_can_scanout_dmabuf;
+	b->base.get_supported_formats = drm_get_supported_formats;
+	b->base.import_dmabuf = drm_import_dmabuf;
+
+	weston_drm_format_array_init(&b->supported_formats);
 
 	weston_setup_vt_switch_bindings(compositor);
 
@@ -3834,12 +4099,14 @@ drm_backend_create(struct weston_compositor *compositor,
 
 	wl_list_init(&device->plane_list);
 	create_sprites(b->drm);
+	ret = populate_supported_formats(b);
+	if (ret < 0)
+		goto err_sprite;
 
 	if (udev_input_init(&b->input,
 			    compositor, b->udev, seat_id,
 			    config->configure_device) < 0) {
 		weston_log("failed to create input devices\n");
-		goto err_sprite;
 	}
 
 	wl_list_init(&b->drm->writeback_connector_list);
@@ -3927,6 +4194,15 @@ drm_backend_create(struct weston_compositor *compositor,
 			weston_log("Error: initializing content-protection "
 				   "support failed.\n");
 
+	if (drm_backend_is_hdr_supported(compositor)) {
+		if (!wl_global_create(compositor->wl_display, &zwp_hdr10_metadata_v1_interface, 1,
+				      compositor, bind_hdr10_metadata)) {
+			weston_log("Error: initializing hdr10 support failed\n");
+		}
+	} else {
+		weston_log("info: HDR is not support\n");
+	}
+
 	ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
 					 &api, sizeof(api));
 
@@ -3941,6 +4217,19 @@ drm_backend_create(struct weston_compositor *compositor,
 		goto err_udev_monitor;
 	}
 
+	if(b->enable_overlay_view){
+		/* create enable-overlay-view*/
+		char *dir, *path;
+		mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+		dir = getenv("XDG_RUNTIME_DIR");
+		path = malloc(strlen(dir) + 40);
+		strcpy(path, dir);
+		strcat(path, "/enable-overlay-view");
+		close(open(path, O_CREAT | O_RDWR, mode));
+		free(path);
+	}
+
 	return b;
 
 err_udev_monitor:
@@ -3951,6 +4240,7 @@ err_drm_source:
 err_udev_input:
 	udev_input_destroy(&b->input);
 err_sprite:
+	weston_drm_format_array_fini(&b->supported_formats);
 	destroy_sprites(b->drm);
 err_create_crtc_list:
 	drmModeFreeResources(res);
@@ -3975,6 +4265,16 @@ config_init_to_defaults(struct weston_drm_backend_config *config)
 {
 	config->renderer = WESTON_RENDERER_AUTO;
 	config->use_pixman_shadow = true;
+#if defined(ENABLE_IMXG2D)
+#if !defined(BUILD_DRM_GBM)
+	config->use_g2d = true;
+#else
+	config->use_g2d = false;
+#endif
+#endif
+	config->shell_width = 0;
+	config->shell_height = 0;
+	config->enable_overlay_view = 0;
 }
 
 WL_EXPORT int
diff --git a/libweston/backend-drm/fb.c b/libweston/backend-drm/fb.c
index 0c2c0f6e..3febdd2f 100644
--- a/libweston/backend-drm/fb.c
+++ b/libweston/backend-drm/fb.c
@@ -206,6 +206,7 @@ drm_fb_addfb(struct drm_device *device, struct drm_fb *fb)
 {
 	int ret = -EINVAL;
 	uint64_t mods[4] = { };
+	int width, height;
 	size_t i;
 
 	ret = drm_fb_maybe_import(device, fb);
@@ -219,7 +220,17 @@ drm_fb_addfb(struct drm_device *device, struct drm_fb *fb)
 		 * for all planes. */
 		for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
 			mods[i] = fb->modifier;
-		ret = drmModeAddFB2WithModifiers(fb->fd, fb->width, fb->height,
+		if (fb->modifier == DRM_FORMAT_MOD_AMPHION_TILED) {
+			width = ALIGNTO (fb->width, 8);
+			height = ALIGNTO (fb->height, 256);
+		}else if(fb->modifier ==DRM_FORMAT_MOD_VIVANTE_SUPER_TILED){
+			width = ALIGNTO (fb->width, 64);
+			height = ALIGNTO (fb->height, 64);
+		} else {
+			width = fb->width;
+			height = fb->height;
+		}
+		ret = drmModeAddFB2WithModifiers(fb->fd, width, height,
 						 fb->format->format,
 						 fb->handles, fb->strides,
 						 fb->offsets, mods, &fb->fb_id,
@@ -364,6 +375,41 @@ drm_fb_destroy_dmabuf(struct drm_fb *fb)
 	drm_fb_destroy(fb);
 }
 
+#ifdef HAVE_GBM_MODIFIERS
+int
+drm_fb_get_gbm_alignment(struct drm_fb *fb)
+{
+	int gbm_aligned = 64;
+
+	if (fb){
+		switch(fb->modifier) {
+			case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC:
+			case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+				gbm_aligned = 64;
+			break;
+			default:
+				gbm_aligned = 1;
+			break;
+		}
+	}
+	return gbm_aligned;
+}
+#endif
+static void
+drm_close_gem_handle(struct linux_dmabuf_buffer *dmabuf)
+{
+	struct drm_backend *b = to_drm_backend(dmabuf->compositor);
+	int i;
+
+	if (dmabuf->gem_handles[0] != 0) {
+		for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+			struct drm_gem_close arg = { dmabuf->gem_handles[i], };
+			drmIoctl (b->drm->drm.fd, DRM_IOCTL_GEM_CLOSE, &arg);
+			dmabuf->gem_handles[i] = 0;
+		}
+	}
+}
+
 static struct drm_fb *
 drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
 		       struct drm_device *device, bool is_opaque,
@@ -378,6 +424,7 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
 	struct drm_backend *backend = device->backend;
 	struct drm_fb *fb;
 	int i;
+	uint32_t gem_handle[MAX_DMABUF_PLANES] = {0};
 	struct gbm_import_fd_modifier_data import_mod = {
 		.width = dmabuf->attributes.width,
 		.height = dmabuf->attributes.height,
@@ -418,23 +465,10 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
 
 	fb->refcnt = 1;
 	fb->type = BUFFER_DMABUF;
-
-	ARRAY_COPY(import_mod.fds, dmabuf->attributes.fd);
-	ARRAY_COPY(import_mod.strides, dmabuf->attributes.stride);
-	ARRAY_COPY(import_mod.offsets, dmabuf->attributes.offset);
-
-	fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
-			       &import_mod, GBM_BO_USE_SCANOUT);
-	if (!fb->bo) {
-		if (try_view_on_plane_failure_reasons)
-			*try_view_on_plane_failure_reasons |=
-				FAILURE_REASONS_GBM_BO_IMPORT_FAILED;
-		goto err_free;
-	}
-
 	fb->width = dmabuf->attributes.width;
 	fb->height = dmabuf->attributes.height;
 	fb->modifier = dmabuf->attributes.modifier[0];
+	fb->dtrc_meta = dmabuf->attributes.dtrc_meta;
 	fb->size = 0;
 	fb->fd = device->drm.fd;
 
@@ -459,6 +493,35 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
 		goto err_free;
 	}
 
+	fb->num_planes = dmabuf->attributes.n_planes;
+	if (dmabuf->gem_handles[0] == 0) {
+		for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+			int ret;
+			ret = drmPrimeFDToHandle (fb->fd, dmabuf->attributes.fd[i], &gem_handle[i]);
+			if (ret) {
+				weston_log ("got gem_handle %x\n", gem_handle[i]);
+				goto err_free;
+			}
+			fb->handles[i] = dmabuf->gem_handles[i] = gem_handle[i];
+		}
+		linux_dmabuf_buffer_gem_handle_close_cb (dmabuf, drm_close_gem_handle);
+	} else {
+		for (i = 0; i < dmabuf->attributes.n_planes; i++)
+			fb->handles[i] = dmabuf->gem_handles[i];
+	}
+
+	if (fb->handles[0] != 0)
+		goto add_fb;
+
+	ARRAY_COPY(import_mod.fds, dmabuf->attributes.fd);
+	ARRAY_COPY(import_mod.strides, dmabuf->attributes.stride);
+	ARRAY_COPY(import_mod.offsets, dmabuf->attributes.offset);
+
+	fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
+			       &import_mod, GBM_BO_USE_SCANOUT);
+	if (!fb->bo)
+		goto err_free;
+
 	fb->num_planes = dmabuf->attributes.n_planes;
 	for (i = 0; i < dmabuf->attributes.n_planes; i++) {
 		union gbm_bo_handle handle;
@@ -472,6 +535,7 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
 		fb->handles[i] = handle.u32;
 	}
 
+add_fb:
 	if (drm_fb_addfb(device, fb) != 0) {
 		if (try_view_on_plane_failure_reasons)
 			*try_view_on_plane_failure_reasons |=
@@ -498,7 +562,17 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
 
 	if (fb) {
 		assert(fb->type == type);
-		return drm_fb_ref(fb);
+
+		bool is_fb_opaque = (!fb->format->opaque_substitute);
+
+		/* If fb->format doesn't meet the opaque requirement and there is
+		 * no reference being taken for this fb, we will convert the fb
+		 * format to a suitable format. */
+		if ((is_opaque != is_fb_opaque) && (fb->refcnt == 0) &&
+		    (fb->fb_id != 0))
+			drm_fb_destroy(fb);
+		else
+			return drm_fb_ref(fb);
 	}
 
 	fb = zalloc(sizeof *fb);
@@ -740,10 +814,13 @@ drm_fb_get_from_paint_node(struct drm_output_state *state,
 		if (!fb)
 			goto unsuitable;
 	} else if (buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) {
-		struct gbm_bo *bo;
+		struct gbm_bo *bo = NULL;
 
-		bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
-				   buffer->resource, GBM_BO_USE_SCANOUT);
+		if(b->enable_overlay_view)
+		{
+			bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+					   buffer->resource, GBM_BO_USE_SCANOUT);
+		}
 		if (!bo)
 			goto unsuitable;
 
diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
index fd5c3044..6621c678 100644
--- a/libweston/backend-drm/kms.c
+++ b/libweston/backend-drm/kms.c
@@ -101,6 +101,7 @@ const struct drm_property_info plane_props[] = {
 		.num_enum_values = WDRM_PLANE_ROTATION__COUNT,
 	 },
 	[WDRM_PLANE_ALPHA] = { .name = "alpha" },
+	[WDRM_PLANE_DTRC_META] = { .name = "dtrc_table_ofs" },
 };
 
 struct drm_property_enum_info dpms_state_enums[] = {
@@ -591,7 +592,7 @@ fallback:
 							 kplane->formats[i]);
 		if (!fmt)
 			return -1;
-		ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
+		ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_LINEAR);
 		if (ret < 0)
 			return -1;
 	}
@@ -840,14 +841,8 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
 	 * legacy PageFlip API doesn't allow us to do clipping either. */
 	assert(scanout_state->src_x == 0);
 	assert(scanout_state->src_y == 0);
-	assert(scanout_state->src_w ==
-		(unsigned) (output->base.current_mode->width << 16));
-	assert(scanout_state->src_h ==
-		(unsigned) (output->base.current_mode->height << 16));
 	assert(scanout_state->dest_x == 0);
 	assert(scanout_state->dest_y == 0);
-	assert(scanout_state->dest_w == scanout_state->src_w >> 16);
-	assert(scanout_state->dest_h == scanout_state->src_h >> 16);
 	/* The legacy SetCrtc API doesn't support fences */
 	assert(scanout_state->in_fence_fd == -1);
 
@@ -1053,6 +1048,28 @@ get_drm_protection_from_weston(enum weston_hdcp_protection weston_protection,
 	}
 }
 
+static int
+drm_protection_from_weston_update(enum weston_hdcp_protection protection)
+{
+	enum weston_hdcp_protection current_protection;
+	static enum weston_hdcp_protection op_protection;
+	static bool op_protection_valid = false;
+
+	current_protection = protection;
+
+	if (!op_protection_valid) {
+		op_protection = current_protection;
+		op_protection_valid = true;
+	}
+
+	if (current_protection != op_protection) {
+		op_protection = current_protection;
+		return 1;
+	}
+
+	return 0;
+}
+
 static void
 drm_connector_set_hdcp_property(struct drm_connector *connector,
 				enum weston_hdcp_protection protection,
@@ -1164,6 +1181,22 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
 	enum writeback_screenshot_state wb_screenshot_state =
 		drm_output_get_writeback_state(output);
 	int ret = 0;
+	int in_fence_fd = -1;
+	int update = 0;
+
+	if(output->gbm_surface) {
+		/* in_fence_fd was not created when
+		 * the buffer_release was not exist or
+		 * the buffer was not used in the output.
+		 */
+		if (output->surface_get_in_fence_fd)
+			in_fence_fd = output->surface_get_in_fence_fd(output->gbm_surface);
+	}
+#if defined(ENABLE_IMXG2D)
+	else if(b->use_g2d && b->g2d_renderer) {
+		in_fence_fd = b->g2d_renderer->get_surface_fence_fd(&output->g2d_image[output->current_image]);
+	}
+#endif
 
 	drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
 		  (*flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "testing" : "applying",
@@ -1218,6 +1251,17 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
 			if (!(*flags & DRM_MODE_ATOMIC_TEST_ONLY))
 				wb_state->state = DRM_OUTPUT_WB_SCREENSHOT_CHECK_FENCE;
 		}
+
+		if (device->hdr_blob_id > 0) {
+			wl_list_for_each(head, &output->base.head_list, base.output_link) {
+				/* checking if the output driver this head */
+				if (head->base.output == &output->base) {
+					connector_add_prop(req, &head->connector, WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
+							device->hdr_blob_id);
+					*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+				}
+			}
+		}
 	} else {
 		ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0);
 		ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0);
@@ -1243,16 +1287,25 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
 	}
 
 	wl_list_for_each(head, &output->base.head_list, base.output_link) {
-		drm_connector_set_hdcp_property(&head->connector,
-						state->protection, req);
+		update = drm_protection_from_weston_update(state->protection);
+		if(update) {
+			drm_connector_set_hdcp_property(&head->connector,
+							state->protection, req);
+			/* checking if the output driver this head */
+			if (head->base.output == &output->base) {
+				*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+			}
+		}
+
 		ret |= drm_connector_set_content_type(&head->connector,
 						      output->content_type, req);
 
 		if (drm_connector_has_prop(&head->connector,
-					   WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) {
+					   WDRM_CONNECTOR_HDR_OUTPUT_METADATA) && device->clean_hdr_blob) {
 			ret |= connector_add_prop(req, &head->connector,
 						  WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
 						  output->hdr_output_metadata_blob_id);
+			*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 		}
 
 		ret |= drm_connector_set_max_bpc(&head->connector, output, req);
@@ -1302,6 +1355,10 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
 			ret |= plane_add_prop(req, plane,
 					      WDRM_PLANE_IN_FENCE_FD,
 					      plane_state->in_fence_fd);
+		} else if (in_fence_fd >= 0 && plane->type == WDRM_PLANE_TYPE_PRIMARY && plane_state->fb) {
+			ret |= plane_add_prop(req, plane,
+					      WDRM_PLANE_IN_FENCE_FD,
+					      in_fence_fd);
 		}
 
 		if (plane->props[WDRM_PLANE_ROTATION].prop_id != 0)
@@ -1321,6 +1378,13 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
 					      WDRM_PLANE_ALPHA,
 					      plane_state->alpha);
 
+		if (plane_state->fb && plane_state->fb->dtrc_meta != plane->dtrc_meta
+		    && plane->type == WDRM_PLANE_TYPE_OVERLAY
+			&& plane_state->fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+		    plane_add_prop(req, plane, WDRM_PLANE_DTRC_META, plane_state->fb->dtrc_meta);
+		    plane->dtrc_meta = plane_state->fb->dtrc_meta;
+		}
+
 		if (ret != 0) {
 			weston_log("couldn't set plane state\n");
 			return ret;
@@ -1358,6 +1422,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
 	uint32_t flags, tear_flag = 0;
 	bool may_tear = true;
 	int ret = 0;
+	drm_magic_t magic;
 
 	if (!req)
 		return -1;
@@ -1477,6 +1542,11 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
 	if (may_tear)
 		tear_flag = DRM_MODE_PAGE_FLIP_ASYNC;
 
+	/*drm master was set by systemd in PM test, try to set the master back.*/
+	if (!(drmGetMagic(device->drm.fd, &magic) == 0 &&
+			drmAuthMagic(device->drm.fd, magic) == 0)) {
+		drmSetMaster(device->drm.fd);
+	}
 	ret = drmModeAtomicCommit(device->drm.fd, req, flags | tear_flag,
 				  device);
 	drm_debug(b, "[atomic] drmModeAtomicCommit\n");
@@ -1512,10 +1582,15 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
 		drm_output_assign_state(output_state, mode);
 
 	device->state_invalid = false;
+	device->clean_hdr_blob = false;
 
 	assert(wl_list_empty(&pending_state->output_list));
 
 out:
+	if (device->hdr_blob_id > 0) {
+		drmModeDestroyPropertyBlob (device->drm.fd, device->hdr_blob_id);
+		device->hdr_blob_id = 0;
+	}
 	drmModeAtomicFree(req);
 	drm_pending_state_free(pending_state);
 	return ret;
diff --git a/libweston/backend-drm/meson.build b/libweston/backend-drm/meson.build
index 1af628d6..27d488b1 100644
--- a/libweston/backend-drm/meson.build
+++ b/libweston/backend-drm/meson.build
@@ -41,6 +41,8 @@ srcs_drm = [
 	linux_dmabuf_unstable_v1_protocol_c,
 	linux_dmabuf_unstable_v1_server_protocol_h,
 	presentation_time_server_protocol_h,
+	hdr10_metadata_unstable_v1_protocol_c,
+	hdr10_metadata_unstable_v1_server_protocol_h,
 ]
 
 deps_drm = [
diff --git a/libweston/backend-drm/state-helpers.c b/libweston/backend-drm/state-helpers.c
index b8fe7d87..6e295de4 100644
--- a/libweston/backend-drm/state-helpers.c
+++ b/libweston/backend-drm/state-helpers.c
@@ -221,6 +221,7 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
 	struct drm_output *output = state->output;
 	struct weston_view *ev = node->view;
 	struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+	struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
 	pixman_region32_t dest_rect;
 	pixman_box32_t *box;
 	struct weston_coord corners[2];
@@ -228,12 +229,30 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
 	uint16_t min_alpha = state->plane->alpha_min;
 	uint16_t max_alpha = state->plane->alpha_max;
 
+	float scale = 1.0;
+	struct weston_matrix scale_mat;
+
 	if (!drm_paint_node_transform_supported(node, state->plane))
 		return false;
 
 	assert(node->valid_transform);
 	state->rotation = drm_rotation_from_output_transform(state->plane, node->transform);
 
+	/* When buffer scale > 1, clients will provide higher resolution buffer data
+	 * on high resolution output. In order to maintain the original output size
+	 * and position, it needs to keep the mode scale and buffer scale equal.
+	 *
+	 * Here, check whether the buffer scale and mode scale are equal, if not,
+	 * We need to judge whether secondary scaling is required during global->output
+	 * coordinate transformation according to buffer scale and mode scale to maintain
+	 * the original output size. */
+	if (viewport->buffer.scale != output->base.current_scale)
+		scale = (float) MAX((viewport->buffer.scale / output->base.current_scale), 1);
+
+	weston_matrix_init(&scale_mat);
+	/* Generate a scaling matrix using the scale parameter above. */
+	weston_matrix_scale(&scale_mat, scale, scale, 1.0);
+
 	/* Update the base weston_plane co-ordinates. */
 	box = pixman_region32_extents(&ev->transform.boundingbox);
 	state->plane->base.x = box->x1;
@@ -249,10 +268,16 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
 
 	box = pixman_region32_extents(&dest_rect);
 
-	state->dest_x = box->x1;
-	state->dest_y = box->y1;
-	state->dest_w = box->x2 - box->x1;
-	state->dest_h = box->y2 - box->y1;
+	/* After the coordinate transformation, do a second scaling to get
+	 * back to the original output size. */
+	corners[0] = weston_matrix_transform_coord(&scale_mat,
+			weston_coord(box->x1, box->y1));
+	corners[1] = weston_matrix_transform_coord(&scale_mat,
+			weston_coord(box->x2, box->y2));
+	state->dest_x = corners[0].x;
+	state->dest_y = corners[0].y;
+	state->dest_w = corners[1].x - corners[0].x;
+	state->dest_h = corners[1].y - corners[0].y;
 
 	/* Now calculate the source rectangle, by transforming the destination
 	 * rectangle by the output to buffer matrix. */
diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c
index b8ec1cbe..cfe52861 100644
--- a/libweston/backend-drm/state-propose.c
+++ b/libweston/backend-drm/state-propose.c
@@ -66,13 +66,18 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
 
 static bool
 drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
-                                         struct drm_output_state *output_state)
+                                         struct drm_pending_state *pending_state)
 {
 	struct drm_plane_state *ps;
-	wl_list_for_each(ps, &output_state->plane_list, link) {
-		if (ps->plane == plane && ps->fb)
-			return true;
+	struct drm_output_state *output_state;
+
+	wl_list_for_each(output_state, &pending_state->output_list, link) {
+		wl_list_for_each(ps, &output_state->plane_list, link) {
+			if (ps->plane == plane && ps->fb)
+				return true;
+		}
 	}
+
 	return false;
 }
 
@@ -442,6 +447,7 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
 	struct drm_output *output = state->output;
 	struct drm_device *device = output->device;
 	struct drm_backend *b = device->backend;
+	struct drm_pending_state *pending_state = device->repaint_data;
 
 	struct drm_plane_state *ps = NULL;
 	struct drm_plane *plane;
@@ -531,7 +537,7 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
 		weston_view_matches_output_entirely(ev, &output->base);
 	scanout_has_view_assigned =
 		drm_output_check_plane_has_view_assigned(output->scanout_plane,
-							 state);
+							 pending_state);
 
 	/* assemble a list with possible candidates */
 	wl_list_for_each(plane, &device->plane_list, link) {
@@ -577,7 +583,7 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
 		if (!drm_plane_is_available(plane, output))
 			continue;
 
-		if (drm_output_check_plane_has_view_assigned(plane, state)) {
+		if (drm_output_check_plane_has_view_assigned(plane, pending_state)) {
 			drm_debug(b, "\t\t\t\t[plane] not trying plane %d: "
 				     "another view already assigned\n",
 				     plane->plane_id);
@@ -610,19 +616,6 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
 			return NULL;
 		}
 
-		if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
-			assert(scanout_state != NULL);
-			if (scanout_state->zpos >= plane->zpos_max) {
-				drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
-					     "candidate list: primary's zpos "
-					     "value (%"PRIu64") higher than "
-					     "plane's maximum value (%"PRIu64")\n",
-					     plane->plane_id, scanout_state->zpos,
-					     plane->zpos_max);
-				continue;
-			}
-		}
-
 		if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
 			zpos = plane->zpos_max;
 		else
@@ -644,6 +637,14 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
 			drm_debug(b, "\t\t\t\t[view] view %p has been placed to "
 				     "%s plane with computed zpos %"PRIu64"\n",
 				     ev, p_name, zpos);
+			/* Check if this ps is underlay plane, if so, the view
+			 * needs through hole on primary plane. */
+			if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
+				assert(scanout_state != NULL);
+				if (scanout_state->zpos > ps->zpos) {
+					pnode->need_through_hole = true;
+				}
+			}
 			break;
 		}
 
@@ -675,12 +676,17 @@ drm_output_propose_state(struct weston_output *output_base,
 	struct drm_output_state *state;
 	struct drm_plane_state *scanout_state = NULL;
 
-	pixman_region32_t renderer_region;
+	pixman_region32_t bottom_region;
 	pixman_region32_t occluded_region;
 
 	bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
 	int ret;
-	uint64_t current_lowest_zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
+	/* Record the current lowest zpos of the overlay planes */
+	uint64_t current_lowest_zpos_overlay = DRM_PLANE_ZPOS_INVALID_PLANE;
+	/* Record the current lowest zpos of the underlay plane */
+	uint64_t current_lowest_zpos_underlay = DRM_PLANE_ZPOS_INVALID_PLANE;
+	/* Record the current lowest zpos when finding planes for view */
+	uint64_t *current_lowest_zpos = NULL;
 
 	assert(!output->state_last);
 	state = drm_output_state_duplicate(output->state_cur,
@@ -718,9 +724,14 @@ drm_output_propose_state(struct weston_output *output_base,
 			drm_output_state_free(state);
 			return NULL;
 		}
-
+#ifdef HAVE_GBM_MODIFIERS
+		int gbm_aligned = drm_fb_get_gbm_alignment (scanout_fb);
+		if (scanout_fb->width != ALIGNTO(output_base->current_mode->width, gbm_aligned) ||
+		    scanout_fb->height != ALIGNTO(output_base->current_mode->height, gbm_aligned)) {
+#else
 		if (scanout_fb->width != output_base->current_mode->width ||
 		    scanout_fb->height != output_base->current_mode->height) {
+#endif
 			drm_debug(b, "\t\t[state] cannot propose mixed mode "
 			             "for output %s (%lu): previous fb has "
 				     "different size\n",
@@ -734,6 +745,10 @@ drm_output_propose_state(struct weston_output *output_base,
 							  plane->state_cur);
 		/* assign the primary the lowest zpos value */
 		scanout_state->zpos = plane->zpos_min;
+		/* Set the current lowest zpos of the underlay plane to
+		 * scanout_state->zpos, the underlay planes need to look
+		 * down from the scanout plane */
+		current_lowest_zpos_underlay = scanout_state->zpos;
 		drm_debug(b, "\t\t[state] using renderer FB ID %lu for mixed "
 			     "mode for output %s (%lu)\n",
 			  (unsigned long) scanout_fb->fb_id, output->base.name,
@@ -742,8 +757,8 @@ drm_output_propose_state(struct weston_output *output_base,
 				scanout_state->zpos);
 	}
 
-	/* - renderer_region contains the total region which which will be
-	 *   covered by the renderer
+	/* - bottom_region contains the total region which which will be
+	 *   covered by the renderer and underlay region.
 	 * - occluded_region contains the total region which which will be
 	 *   covered by the renderer and hardware planes, where the view's
 	 *   visible-and-opaque region is added in both cases (the view's
@@ -751,7 +766,7 @@ drm_output_propose_state(struct weston_output *output_base,
 	 *   to skip the view, if it is completely occluded; includes the
 	 *   situation where occluded_region covers entire output's region.
 	 */
-	pixman_region32_init(&renderer_region);
+	pixman_region32_init(&bottom_region);
 	pixman_region32_init(&occluded_region);
 
 	wl_list_for_each(pnode, &output->base.paint_node_z_order_list,
@@ -768,6 +783,10 @@ drm_output_propose_state(struct weston_output *output_base,
 		          ev, output->base.name,
 			  (unsigned long) output->base.id);
 
+		current_lowest_zpos = &current_lowest_zpos_overlay;
+		current_lowest_zpos_underlay = MIN(current_lowest_zpos_underlay,
+		             current_lowest_zpos_overlay);
+
 		/* If this view doesn't touch our output at all, there's no
 		 * reason to do anything with it. */
 		/* TODO: turn this into assert once z_order_list is pruned. */
@@ -844,14 +863,15 @@ drm_output_propose_state(struct weston_output *output_base,
 		}
 
 		/* Since we process views from top to bottom, we know that if
-		 * the view intersects the calculated renderer region, it must
-		 * be part of, or occluded by, it, and cannot go on a plane. */
-		pixman_region32_intersect(&surface_overlap, &renderer_region,
+		 * the view intersects the calculated bottom region, it must
+		 * be part of, or occluded by, it, and cannot go on an overlay
+		 * plane. */
+		pixman_region32_intersect(&surface_overlap, &bottom_region,
 					  &clipped_view);
 		if (pixman_region32_not_empty(&surface_overlap)) {
-			drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
+			drm_debug(b, "\t\t\t\t[view] assign view %p to underlay plane "
 			             "(occluded by renderer views)\n", ev);
-			force_renderer = true;
+			current_lowest_zpos = &current_lowest_zpos_underlay;
 		}
 		pixman_region32_fini(&surface_overlap);
 
@@ -873,10 +893,10 @@ drm_output_propose_state(struct weston_output *output_base,
 		/* Now try to place it on a plane if we can. */
 		if (!force_renderer) {
 			drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n",
-				      current_lowest_zpos);
+				      *current_lowest_zpos);
 			ps = drm_output_find_plane_for_view(state, pnode, mode,
 							    scanout_state,
-							    current_lowest_zpos);
+							    *current_lowest_zpos);
 		} else {
 			/* We are forced to place the view in the renderer, set
 			 * the failure reason accordingly. */
@@ -885,9 +905,9 @@ drm_output_propose_state(struct weston_output *output_base,
 		}
 
 		if (ps) {
-			current_lowest_zpos = ps->zpos;
+			*current_lowest_zpos = ps->zpos;
 			drm_debug(b, "\t\t\t[plane] next zpos to use %"PRIu64"\n",
-				      current_lowest_zpos);
+				      *current_lowest_zpos);
 		} else if (!ps && !renderer_ok) {
 			drm_debug(b, "\t\t[view] failing state generation: "
 				      "placing view %p to renderer not allowed\n",
@@ -895,14 +915,17 @@ drm_output_propose_state(struct weston_output *output_base,
 			pixman_region32_fini(&clipped_view);
 			goto err_region;
 		} else if (!ps) {
+			drm_debug(b, "\t\t\t\t[view] view %p will be placed "
+				     "on the renderer\n", ev);
+		}
+
+		if (!ps || (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED &&
+		    ps->zpos < scanout_state->zpos)) {
 			/* clipped_view contains the area that's going to be
 			 * visible on screen; add this to the renderer region */
-			pixman_region32_union(&renderer_region,
-					      &renderer_region,
+			pixman_region32_union(&bottom_region,
+					      &bottom_region,
 					      &clipped_view);
-
-			drm_debug(b, "\t\t\t\t[view] view %p will be placed "
-				     "on the renderer\n", ev);
 		}
 
 		/* Opaque areas of our clipped view occlude areas behind it;
@@ -921,7 +944,7 @@ drm_output_propose_state(struct weston_output *output_base,
 		pixman_region32_fini(&clipped_view);
 	}
 
-	pixman_region32_fini(&renderer_region);
+	pixman_region32_fini(&bottom_region);
 	pixman_region32_fini(&occluded_region);
 
 	/* In renderer-only mode, we can't test the state as we don't have a
@@ -952,7 +975,7 @@ drm_output_propose_state(struct weston_output *output_base,
 	return state;
 
 err_region:
-	pixman_region32_fini(&renderer_region);
+	pixman_region32_fini(&bottom_region);
 	pixman_region32_fini(&occluded_region);
 err:
 	drm_output_state_free(state);
@@ -1072,6 +1095,7 @@ drm_assign_planes(struct weston_output *output_base)
 			drm_debug(b, "\t[repaint] view %p using renderer "
 				     "composition\n", ev);
 			weston_view_move_to_plane(ev, primary);
+			pnode->need_through_hole = false;
 		}
 
 		if (!target_plane ||
diff --git a/libweston/backend.h b/libweston/backend.h
index bfd15572..a8ad819d 100644
--- a/libweston/backend.h
+++ b/libweston/backend.h
@@ -102,6 +102,12 @@ struct weston_backend {
 	 */
 	bool (*can_scanout_dmabuf)(struct weston_backend *backend,
 				   struct linux_dmabuf_buffer *buffer);
+
+	const struct weston_drm_format_array *
+			(*get_supported_formats)(struct weston_compositor *ec);
+
+	bool (*import_dmabuf)(struct weston_compositor* compositor,
+					struct linux_dmabuf_buffer *dmabuf);
 };
 
 /* weston_head */
diff --git a/libweston/compositor.c b/libweston/compositor.c
index b806a0a8..e3b9afd9 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -196,6 +196,8 @@ weston_paint_node_create(struct weston_surface *surface,
 		break;
 	}
 
+	pnode->need_through_hole = false;
+
 	pnode->surface = surface;
 	wl_list_insert(&surface->paint_node_list, &pnode->surface_link);
 
@@ -1366,20 +1368,15 @@ weston_view_update_transform_disable(struct weston_view *view)
 				  view->geometry.pos_offset.y);
 
 	if (view->alpha == 1.0) {
-		if (view->surface->is_opaque) {
-			pixman_region32_copy(&view->transform.opaque,
-					     &view->transform.boundingbox);
-		} else {
-			pixman_region32_copy(&view->transform.opaque,
-					     &view->surface->opaque);
-			if (view->geometry.scissor_enabled)
-				pixman_region32_intersect(&view->transform.opaque,
-							  &view->transform.opaque,
-							  &view->geometry.scissor);
-			pixman_region32_translate(&view->transform.opaque,
-						  view->geometry.pos_offset.x,
-						  view->geometry.pos_offset.y);
-		}
+		pixman_region32_copy(&view->transform.opaque,
+				     &view->surface->opaque);
+		if (view->geometry.scissor_enabled)
+			pixman_region32_intersect(&view->transform.opaque,
+						  &view->transform.opaque,
+						  &view->geometry.scissor);
+		pixman_region32_translate(&view->transform.opaque,
+					  view->geometry.pos_offset.x,
+					  view->geometry.pos_offset.y);
 	}
 }
 
@@ -1422,36 +1419,20 @@ weston_view_update_transform_enable(struct weston_view *view)
 	surfbox = pixman_region32_extents(&surfregion);
 
 	view_compute_bbox(view, surfbox, &view->transform.boundingbox);
+	pixman_region32_fini(&surfregion);
 
 	if (view->alpha == 1.0 &&
 	    matrix->type == WESTON_MATRIX_TRANSFORM_TRANSLATE) {
-		if (view->surface->is_opaque) {
-			pixman_region32_copy(&view->transform.opaque,
-					     &view->transform.boundingbox);
-		} else {
-			pixman_region32_copy(&view->transform.opaque,
-					     &view->surface->opaque);
-			if (view->geometry.scissor_enabled)
-				pixman_region32_intersect(&view->transform.opaque,
-							  &view->transform.opaque,
-							  &view->geometry.scissor);
-			pixman_region32_translate(&view->transform.opaque,
-						  matrix->d[12],
-						  matrix->d[13]);
-		}
-	} else if (view->alpha == 1.0 &&
-		 matrix->type < WESTON_MATRIX_TRANSFORM_ROTATE &&
-		 pixman_region32_n_rects(&surfregion) == 1 &&
-		 (pixman_region32_equal(&surfregion, &view->surface->opaque) ||
-		  view->surface->is_opaque)) {
-		/* The whole surface is opaque and it is only translated and
-		 * scaled and after applying the scissor, the result is still
-		 * a single rectangle. In this case the boundingbox matches the
-		 * view exactly and can be used as opaque area. */
 		pixman_region32_copy(&view->transform.opaque,
-				     &view->transform.boundingbox);
+				     &view->surface->opaque);
+		if (view->geometry.scissor_enabled)
+			pixman_region32_intersect(&view->transform.opaque,
+						  &view->transform.opaque,
+						  &view->geometry.scissor);
+		pixman_region32_translate(&view->transform.opaque,
+					  matrix->d[12],
+					  matrix->d[13]);
 	}
-	pixman_region32_fini(&surfregion);
 
 	return 0;
 }
@@ -3865,7 +3846,7 @@ weston_surface_is_pending_viewport_source_valid(
 	if (vp->buffer.src_width == wl_fixed_from_int(-1))
 		return true;
 
-	if (pend->newly_attached) {
+	if (pend->newly_attached || pend->buffer_viewport.changed) {
 		if (pend->buffer) {
 			convert_size_by_transform_scale(&width_from_buffer,
 							&height_from_buffer,
@@ -8807,8 +8788,15 @@ weston_compositor_import_dmabuf(struct weston_compositor *compositor,
 				struct linux_dmabuf_buffer *buffer)
 {
 	struct weston_renderer *renderer;
+	struct weston_backend *backend;
 
 	renderer = compositor->renderer;
+	backend = compositor->backend;
+
+	/* first try backend import, if fail, fallback to render import */
+	if (backend->import_dmabuf)
+		if(backend->import_dmabuf(compositor, buffer))
+			return true;
 
 	if (renderer->import_dmabuf == NULL)
 		return false;
diff --git a/libweston/launcher-libseat.c b/libweston/launcher-libseat.c
index 8c0abb9a..73fc85a7 100644
--- a/libweston/launcher-libseat.c
+++ b/libweston/launcher-libseat.c
@@ -118,14 +118,19 @@ seat_open_device(struct weston_launcher *launcher, const char *path, int flags)
 	struct launcher_libseat *wl = wl_container_of(launcher, wl, base);
 	struct launcher_libseat_device *dev;
 	struct stat st;
+	int loop = 0;
 
 	dev = zalloc(sizeof(struct launcher_libseat_device));
 	if (dev == NULL) {
 		goto err_alloc;
 	}
 
+retry:
 	dev->device_id = libseat_open_device(wl->seat, path, &dev->fd);
 	if (dev->device_id == -1) {
+		sleep(1);
+		if(loop++ < 10)
+			goto retry;
 		goto err_open;
 	}
 
diff --git a/libweston/launcher-logind.c b/libweston/launcher-logind.c
index c9e3e185..5b73bdae 100644
--- a/libweston/launcher-logind.c
+++ b/libweston/launcher-logind.c
@@ -77,6 +77,7 @@ launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
 	bool b;
 	int r, fd;
 	dbus_bool_t paused;
+	int loop = 0;
 
 	m = dbus_message_new_method_call("org.freedesktop.login1",
 					 wl->spath,
@@ -94,10 +95,14 @@ launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
 		goto err_unref;
 	}
 
+retry:
 	reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
 							  -1, NULL);
 	if (!reply) {
+		sleep(1);
 		weston_log("logind: TakeDevice on %d:%d failed.\n", major, minor);
+		if(loop++ < 10)
+			goto retry;
 		r = -ENODEV;
 		goto err_unref;
 	}
@@ -496,10 +501,11 @@ device_paused(struct launcher_logind *wl, DBusMessage *m)
 	 * "gone" means the device is gone. We handle it the same as "force" as
 	 * a following udev event will be caught, too.
 	 *
-	 * If it's our main DRM device, tell the compositor to go asleep. */
-
+	 * If it's our main DRM device and not "gone", tell the compositor to go asleep. */
 	if (!strcmp(type, "pause"))
 		launcher_logind_pause_device_complete(wl, major, minor);
+	else if (strcmp(type, "gone") == 0)
+		return;
 
 	if (wl->sync_drm && wl->compositor->backend->device_changed)
 		wl->compositor->backend->device_changed(wl->compositor->backend,
diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h
index ddd39818..64fa93f6 100644
--- a/libweston/libweston-internal.h
+++ b/libweston/libweston-internal.h
@@ -554,6 +554,8 @@ struct weston_paint_node {
 	bool surf_xform_valid;
 
 	uint32_t try_view_on_plane_failure_reasons;
+
+	bool need_through_hole;
 };
 
 struct weston_paint_node *
diff --git a/libweston/linux-dmabuf.c b/libweston/linux-dmabuf.c
index 1a9e31d5..2e8fab59 100644
--- a/libweston/linux-dmabuf.c
+++ b/libweston/linux-dmabuf.c
@@ -36,6 +36,7 @@
 #include <libweston/libweston.h>
 #include "linux-dmabuf.h"
 #include "linux-dmabuf-unstable-v1-server-protocol.h"
+#include "backend.h"
 #include "shared/os-compatibility.h"
 #include "shared/helpers.h"
 #include "libweston-internal.h"
@@ -147,6 +148,9 @@ destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
 	assert(buffer->buffer_resource == resource);
 	assert(!buffer->params_resource);
 
+	if (buffer->gem_handle_close_func)
+		buffer->gem_handle_close_func(buffer);
+
 	if (buffer->user_data_destroy_func)
 		buffer->user_data_destroy_func(buffer);
 
@@ -343,12 +347,35 @@ params_create_immed(struct wl_client *client,
 			     format, flags);
 }
 
+static void
+params_add_dtrc_meta(struct wl_client *client,
+		    struct wl_resource *params_resource,
+		    uint32_t rfc_chroma_offset,
+		    uint32_t rfc_luma_offset)
+{
+	struct linux_dmabuf_buffer *buffer;
+
+	buffer = wl_resource_get_user_data(params_resource);
+	if (!buffer) {
+		wl_resource_post_error(params_resource,
+			ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+			"params was already used to create a wl_buffer");
+		return;
+	}
+
+	assert(buffer->params_resource == params_resource);
+	assert(!buffer->buffer_resource);
+
+	buffer->attributes.dtrc_meta =  rfc_luma_offset | ((uint64_t)rfc_chroma_offset << 32);
+}
+
 static const struct zwp_linux_buffer_params_v1_interface
 zwp_linux_buffer_params_implementation = {
 	params_destroy,
 	params_add,
 	params_create,
-	params_create_immed
+	params_create_immed,
+	params_add_dtrc_meta
 };
 
 static void
@@ -964,6 +991,21 @@ linux_dmabuf_buffer_get(struct wl_resource *resource)
 	return buffer;
 }
 
+/** Set drmbackend-private data
+ *
+ * set the drm gem handle close callback in the linux_dmabuf_buffer
+ *
+ * \param buffer The linux_dmabuf_buffer object to set for.
+ * \param func Destructor function to be called to close gem handle
+ *             when the linux_dmabuf_buffer gets destroyed.
+ */
+WL_EXPORT void
+linux_dmabuf_buffer_gem_handle_close_cb(struct linux_dmabuf_buffer *buffer,
+				  dmabuf_gem_handle_close_func func)
+{
+	buffer->gem_handle_close_func = func;
+}
+
 /** Set renderer-private data
  *
  * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
@@ -1064,6 +1106,27 @@ bind_linux_dmabuf(struct wl_client *client,
 			}
 		}
 	}
+
+	if (compositor->backend->get_supported_formats) {
+		supported_formats = compositor->backend->get_supported_formats(compositor);
+		wl_array_for_each(fmt, &supported_formats->arr) {
+			modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
+			for (i = 0; i < num_modifiers; i++) {
+				if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
+					uint32_t modifier_lo = modifiers[i] & 0xFFFFFFFF;
+					uint32_t modifier_hi = modifiers[i] >> 32;
+					zwp_linux_dmabuf_v1_send_modifier(resource,
+									  fmt->format,
+									  modifier_hi,
+									  modifier_lo);
+				} else if (modifiers[i] == DRM_FORMAT_MOD_LINEAR ||
+					   modifiers[i] == DRM_FORMAT_MOD_INVALID) {
+					zwp_linux_dmabuf_v1_send_format(resource,
+									fmt->format);
+				}
+			}
+		}
+	}
 }
 
 /** Advertise linux_dmabuf support
diff --git a/libweston/linux-dmabuf.h b/libweston/linux-dmabuf.h
index 7508eb5e..4f6c4802 100644
--- a/libweston/linux-dmabuf.h
+++ b/libweston/linux-dmabuf.h
@@ -33,6 +33,8 @@
 struct linux_dmabuf_buffer;
 typedef void (*dmabuf_user_data_destroy_func)(
 			struct linux_dmabuf_buffer *buffer);
+typedef void (*dmabuf_gem_handle_close_func)(
+			struct linux_dmabuf_buffer *buffer);
 
 struct dmabuf_attributes {
 	int32_t width;
@@ -44,6 +46,7 @@ struct dmabuf_attributes {
 	uint32_t offset[MAX_DMABUF_PLANES];
 	uint32_t stride[MAX_DMABUF_PLANES];
 	uint64_t modifier[MAX_DMABUF_PLANES];
+	uint64_t dtrc_meta;
 };
 
 struct linux_dmabuf_buffer {
@@ -72,6 +75,9 @@ struct linux_dmabuf_buffer {
 
 	/**< marked as scan-out capable, avoids any composition */
 	bool direct_display;
+
+	uint32_t gem_handles[MAX_DMABUF_PLANES];
+	dmabuf_gem_handle_close_func gem_handle_close_func;
 };
 
 enum weston_dmabuf_feedback_tranche_preference {
@@ -153,6 +159,10 @@ weston_direct_display_setup(struct weston_compositor *compositor);
 struct linux_dmabuf_buffer *
 linux_dmabuf_buffer_get(struct wl_resource *resource);
 
+void
+linux_dmabuf_buffer_gem_handle_close_cb(struct linux_dmabuf_buffer *buffer,
+				  dmabuf_gem_handle_close_func func);
+
 void
 linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
 				  void *data,
diff --git a/libweston/meson.build b/libweston/meson.build
index cb06c1c5..a6d53a0b 100644
--- a/libweston/meson.build
+++ b/libweston/meson.build
@@ -102,6 +102,14 @@ if get_option('backend-vnc')
 	deps_libweston += dep_pam
 endif
 
+if get_option('renderer-g2d')
+	dep_egl = dependency('egl', required: false)
+	if not dep_egl.found()
+		error('libweston + g2d-renderer requires egl which was not found. Or, you can use \'-Drenderer-g2d=false\'.')
+	endif
+	deps_libweston += dep_egl
+endif
+
 lib_weston = shared_library(
 	'weston-@0@'.format(libweston_major),
 	srcs_libweston,
@@ -262,6 +270,7 @@ dep_lib_gl_borders = declare_dependency(
 
 subdir('color-lcms')
 subdir('renderer-gl')
+subdir('renderer-g2d')
 subdir('backend-drm')
 subdir('backend-headless')
 subdir('backend-pipewire')
diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c
index 1e8e5099..ae3427d3 100644
--- a/libweston/pixel-formats.c
+++ b/libweston/pixel-formats.c
@@ -471,6 +471,16 @@ static const struct pixel_format_info pixel_format_table[] = {
 		.hsub = 2,
 		.vsub = 2,
 	},
+	{
+#if USE_DRM_FORMAT_NV15
+		DRM_FORMAT(NV15),
+#else
+		DRM_FORMAT(NV12_10LE40),
+#endif
+		.num_planes = 2,
+		.hsub = 2,
+		.vsub = 2,
+	},
 	{
 		DRM_FORMAT(NV21),
 		SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
diff --git a/libweston/renderer-g2d/g2d-renderer.c b/libweston/renderer-g2d/g2d-renderer.c
new file mode 100644
index 00000000..ef3aab5d
--- /dev/null
+++ b/libweston/renderer-g2d/g2d-renderer.c
@@ -0,0 +1,2504 @@
+/*
+ * Copyright (c) 2016 Freescale Semiconductor, Inc.
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2015 Collabora, Ltd.
+ * Copyright 2018 NXP
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <float.h>
+#include <math.h>
+#include <assert.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <drm_fourcc.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <libweston/libweston.h>
+#include "g2d-renderer.h"
+#include "output-capture.h"
+#include "vertex-clipping.h"
+#include "linux-dmabuf.h"
+#include "linux-dmabuf-unstable-v1-server-protocol.h"
+#include "linux-explicit-synchronization.h"
+#include "shared/fd-util.h"
+#include "shared/helpers.h"
+#include "shared/platform.h"
+#include "pixel-formats.h"
+#include "shared/xalloc.h"
+
+#define BUFFER_DAMAGE_COUNT 3
+#define ALIGN_TO_16(a) (((a) + 15) & ~15)
+#define ALIGN_TO_64(a) (((a) + 63) & ~63)
+
+#ifdef ENABLE_EGL
+static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
+#ifndef PFNEGLUPDATEWAYLANDBUFFERWL
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUPDATEWAYLANDBUFFERWL)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute);
+#endif
+#endif
+
+enum g2d_rotation_angle
+{
+	/* rotation angle 0 */
+	G2D_ROTATION_ANGLE_0 = 0x10,
+
+	/* clockwise rotation */
+	G2D_ROTATION_ANGLE_POSITIVE_90 = 0x20,
+	G2D_ROTATION_ANGLE_POSITIVE_180 = 0x40,
+	G2D_ROTATION_ANGLE_POSITIVE_270 = 0x80,
+
+	/* Anticlockwise rotation */
+	G2D_ROTATION_ANGLE_NEGATIVE_90 = 0x08,
+	G2D_ROTATION_ANGLE_NEGATIVE_180 = 0x04,
+	G2D_ROTATION_ANGLE_NEGATIVE_270 = 0x02,
+};
+
+struct wl_viv_buffer
+{
+	struct wl_resource *resource;
+	void *surface;
+	signed int width;
+	signed int height;
+	enum g2d_format format;
+	unsigned int alignedWidth;
+	unsigned int alignedHeight;
+	unsigned int physical[3];
+	unsigned int gpuBaseAddr;
+	enum g2d_tiling tiling;
+	signed int fd;
+
+	unsigned int ts_addr;
+	unsigned int fc_enabled;
+	unsigned int fcValue;
+	unsigned int fcValueUpper;
+	unsigned int compressed;
+	unsigned int tileStatus_enabled;
+};
+
+typedef struct _g2dRECT
+{
+	int left;
+	int top;
+	int right;
+	int bottom;
+} g2dRECT;
+
+struct g2d_output_state {
+	int current_buffer;
+	struct weston_size fb_size;
+	struct weston_geometry area;
+	pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
+	struct g2d_surfaceEx *drm_hw_buffer;
+	int width;
+	int height;
+};
+
+struct g2d_surface_state {
+	float color[4];
+	bool solid_clear;
+	int clcolor;
+	struct weston_buffer_reference buffer_ref;
+	struct weston_buffer_release_reference buffer_release_ref;
+	int pitch; /* in pixels */
+	int attached;
+	pixman_region32_t texture_damage;
+	struct g2d_surfaceEx g2d_surface;
+	struct g2d_buf *shm_buf;
+	struct g2d_buf *dma_buf;
+	int shm_buf_length;
+	int bpp;
+
+	struct weston_surface *surface;
+	struct wl_listener surface_destroy_listener;
+	struct wl_listener renderer_destroy_listener;
+};
+
+struct g2d_renderer {
+	struct weston_renderer base;
+	struct wl_signal destroy_signal;
+#ifdef ENABLE_EGL
+	NativeDisplayType display;
+	EGLDisplay egl_display;
+	struct wl_display *wl_display;
+	PFNEGLBINDWAYLANDDISPLAYWL bind_display;
+	PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
+	PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
+	PFNEGLUPDATEWAYLANDBUFFERWL update_buffer;
+
+	EGLDeviceEXT egl_device;
+	const char *drm_device;
+
+	PFNEGLQUERYDISPLAYATTRIBEXTPROC query_display_attrib;
+	PFNEGLQUERYDEVICESTRINGEXTPROC query_device_string;
+	bool has_device_query;
+	bool has_bind_display;
+
+	bool has_dmabuf_import_modifiers;
+	PFNEGLQUERYDMABUFFORMATSEXTPROC query_dmabuf_formats;
+	PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dmabuf_modifiers;
+#endif
+	void *handle;
+	int use_drm;
+	struct weston_drm_format_array supported_formats;
+};
+
+static int
+g2d_renderer_create_surface(struct weston_surface *surface);
+
+static inline struct g2d_surface_state *
+get_surface_state(struct weston_surface *surface)
+{
+	if (!surface->renderer_state)
+		g2d_renderer_create_surface(surface);
+
+	return (struct g2d_surface_state *)surface->renderer_state;
+}
+
+static inline struct g2d_renderer *
+get_renderer(struct weston_compositor *ec)
+{
+	return (struct g2d_renderer *)ec->renderer;
+}
+
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#define min(a, b) (((a) > (b)) ? (b) : (a))
+/*
+ * Compute the boundary vertices of the intersection of the global coordinate
+ * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
+ * 'surf_rect' when transformed from surface coordinates into global coordinates.
+ * The vertices are written to 'ex' and 'ey', and the return value is the
+ * number of vertices. Vertices are produced in clockwise winding order.
+ * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
+ * polygon area.
+ */
+static int
+calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
+		pixman_box32_t *surf_rect, struct weston_coord *e)
+{
+
+	struct clip_context ctx;
+	int i, n;
+	float min_x, max_x, min_y, max_y;
+	struct weston_surface *es = ev->surface;
+	struct weston_coord_surface tmp[4] = {
+		weston_coord_surface(surf_rect->x1, surf_rect->y1, es),
+		weston_coord_surface(surf_rect->x2, surf_rect->y1, es),
+		weston_coord_surface(surf_rect->x2, surf_rect->y2, es),
+		weston_coord_surface(surf_rect->x1, surf_rect->y2, es),
+	};
+	struct polygon8 surf;
+
+	surf.n = 4;
+
+	ctx.clip.x1 = rect->x1;
+	ctx.clip.y1 = rect->y1;
+	ctx.clip.x2 = rect->x2;
+	ctx.clip.y2 = rect->y2;
+
+	/* transform surface to screen space: */
+	for (i = 0; i < surf.n; i++)
+		surf.pos[i] = weston_coord_surface_to_global(ev, tmp[i]).c;
+
+	/* find bounding box: */
+	min_x = max_x = surf.pos[0].x;
+	min_y = max_y = surf.pos[0].y;
+
+	for (i = 1; i < surf.n; i++) {
+		min_x = MIN(min_x, surf.pos[i].x);
+		max_x = MAX(max_x, surf.pos[i].x);
+		min_y = MIN(min_y, surf.pos[i].y);
+		max_y = MAX(max_y, surf.pos[i].y);
+	}
+
+	/* First, simple bounding box check to discard early transformed
+	 * surface rects that do not intersect with the clip region:
+	 */
+	if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
+		(min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
+		return 0;
+
+	/* Simple case, bounding box edges are parallel to surface edges,
+	 * there will be only four edges.  We just need to clip the surface
+	 * vertices to the clip rect bounds:
+	 */
+	if (!ev->transform.enabled)
+		return clip_simple(&ctx, &surf, e);
+
+	/* Transformed case: use a general polygon clipping algorithm to
+	 * clip the surface rectangle with each side of 'rect'.
+	 * The algorithm is Sutherland-Hodgman, as explained in
+	 * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
+	 * but without looking at any of that code.
+	 */
+	n = clip_transformed(&ctx, &surf, e);
+
+	if (n < 3)
+		return 0;
+
+	return n;
+
+}
+
+static void
+calculate_rect_with_transform(int surfaceWidth, int surfaceHeight,
+				  uint32_t transform, g2dRECT *rect)
+{
+	g2dRECT tmp = *rect;
+
+	switch (transform) {
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+	default:
+		break;
+	case WL_OUTPUT_TRANSFORM_270:
+		rect->right = surfaceWidth - tmp.top;
+		rect->left = rect->right - (tmp.bottom - tmp.top);
+		rect->top = tmp.left;
+		rect->bottom = rect->top + (tmp.right - tmp.left);
+		break;
+	case WL_OUTPUT_TRANSFORM_90:
+		rect->left = tmp.top;
+		rect->right = rect->left + (tmp.bottom - tmp.top);
+		rect->bottom = surfaceHeight - tmp.left;
+		rect->top = rect->bottom - (tmp.right - tmp.left);
+		break;
+	case WL_OUTPUT_TRANSFORM_180:
+		rect->left = surfaceWidth - tmp.right;
+		rect->right = rect->left + (tmp.right - tmp.left);
+		rect->bottom = surfaceHeight - tmp.top;
+		rect->top = rect->bottom - (tmp.bottom - tmp.top);
+		break;
+	}
+}
+
+static void
+convert_size_by_view_transform(int *width_out, int *height_out, int width, int height, uint32_t transform)
+{
+		switch (transform) {
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+	case WL_OUTPUT_TRANSFORM_180:
+	case WL_OUTPUT_TRANSFORM_FLIPPED:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+	default:
+		*width_out = width;
+		*height_out = height;
+		break;
+	case WL_OUTPUT_TRANSFORM_90:
+	case WL_OUTPUT_TRANSFORM_270:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+		*width_out = height;
+		*height_out = width;
+		break;
+	}
+}
+
+static enum g2d_rotation
+convert_transform_to_rot(uint32_t view_transform, uint32_t output_transform)
+{
+	uint8_t angle = G2D_ROTATION_ANGLE_0;
+	enum g2d_rotation rot;
+
+	/* First, rotate according to the angle set by the client. */
+	angle = angle << view_transform;
+	/* Then, rotate according to the angle of the output. */
+	angle = angle >> output_transform;
+
+	switch(angle) {
+	case G2D_ROTATION_ANGLE_0:
+	default:
+		rot = G2D_ROTATION_0;
+		break;
+	case G2D_ROTATION_ANGLE_POSITIVE_270:
+	case G2D_ROTATION_ANGLE_NEGATIVE_90:
+		rot = G2D_ROTATION_90;
+		break;
+	case G2D_ROTATION_ANGLE_POSITIVE_90:
+	case G2D_ROTATION_ANGLE_NEGATIVE_270:
+		rot = G2D_ROTATION_270;
+		break;
+	case G2D_ROTATION_ANGLE_POSITIVE_180:
+	case G2D_ROTATION_ANGLE_NEGATIVE_180:
+		rot = G2D_ROTATION_180;
+		break;
+	}
+	return rot;
+}
+
+static inline struct g2d_output_state *
+get_output_state(struct weston_output *output)
+{
+	return (struct g2d_output_state *)output->renderer_state;
+}
+
+static int
+g2d_getG2dFormat_from_pixman(pixman_format_code_t Format, enum g2d_format* g2dFormat)
+{
+	switch(Format)
+	{
+	case PIXMAN_r5g6b5:
+		*g2dFormat = G2D_RGB565;
+		break;
+	case PIXMAN_a8b8g8r8:
+		*g2dFormat = G2D_RGBA8888;
+		break;
+	case PIXMAN_x8b8g8r8:
+		*g2dFormat = G2D_RGBX8888;
+		break;
+	case PIXMAN_a8r8g8b8:
+		*g2dFormat = G2D_BGRA8888;
+		break;
+	case PIXMAN_x8r8g8b8 :
+		*g2dFormat = G2D_BGRX8888;
+		break;
+	case PIXMAN_b5g6r5:
+		*g2dFormat = G2D_BGR565;
+		break;
+	case PIXMAN_b8g8r8a8:
+		*g2dFormat = G2D_ARGB8888;
+		break;
+	case PIXMAN_r8g8b8a8:
+		*g2dFormat = G2D_ABGR8888;
+		break;
+	case PIXMAN_b8g8r8x8:
+		*g2dFormat = G2D_XRGB8888;
+		break;
+	case PIXMAN_r8g8b8x8:
+		*g2dFormat = G2D_XBGR8888;
+		break;
+	case PIXMAN_yv12:
+		*g2dFormat = G2D_YV12;
+		break;
+	case PIXMAN_yuy2:
+		*g2dFormat = G2D_YUYV;
+		break;
+	default:
+		weston_log("Error in function %s, Format(%d) not supported\n", __func__, Format);
+		return -1;
+	}
+	return 0;
+}
+
+static void printG2dSurfaceInfo(struct g2d_surfaceEx* g2dSurface, const char* msg)
+{
+	weston_log("%s physicAddr = %x left = %d right = %d top=%d bottom=%d stride= %d tiling = %d, format=%d \n",
+				msg,
+				g2dSurface->base.planes[0],
+				g2dSurface->base.left,
+				g2dSurface->base.right,
+				g2dSurface->base.top,
+				g2dSurface->base.bottom,
+				g2dSurface->base.stride,
+				g2dSurface->tiling,
+				g2dSurface->base.format);
+}
+
+static int
+get_g2dSurface(struct wl_viv_buffer *buffer, struct g2d_surfaceEx *g2dSurface)
+{
+	if(buffer->width <= 0 || buffer->height <= 0)
+	{
+		weston_log("invalid EGL buffer in function %s\n", __func__);
+		return -EINVAL;
+	}
+	g2dSurface->base.format = buffer->format;
+	g2dSurface->tiling = buffer->tiling;
+	g2dSurface->base.planes[0] = buffer->physical[0] + buffer->gpuBaseAddr;
+	g2dSurface->base.planes[1] = buffer->physical[1] + buffer->gpuBaseAddr;
+	g2dSurface->base.planes[2] = buffer->physical[2] + buffer->gpuBaseAddr;
+	g2dSurface->base.left = 0;
+	g2dSurface->base.top = 0;
+	g2dSurface->base.right = buffer->width;
+	g2dSurface->base.bottom = buffer->height;
+	g2dSurface->base.stride = buffer->alignedWidth;
+	g2dSurface->base.width	= buffer->width;
+	g2dSurface->base.height = buffer->height;
+	g2dSurface->base.rot	= G2D_ROTATION_0;
+
+	if(buffer->ts_addr && buffer->tileStatus_enabled)
+	{
+		g2dSurface->tiling             |= G2D_TILED_STATUS;
+		g2dSurface->ts.ts_addr         = buffer->ts_addr;
+		g2dSurface->ts.fc_enabled      = buffer->fc_enabled;
+		g2dSurface->ts.fc_value        = buffer->fcValue;
+		g2dSurface->ts.fc_value_upper  = buffer->fcValueUpper;
+	}
+
+	return 0;
+}
+
+static void
+g2d_SetSurfaceRect(struct g2d_surfaceEx* g2dSurface, g2dRECT* rect)
+{
+	if(g2dSurface && rect)
+	{
+		g2dSurface->base.left	= rect->left;
+		g2dSurface->base.top	= rect->top;
+		g2dSurface->base.right	= rect->right;
+		g2dSurface->base.bottom = rect->bottom;
+	}
+}
+
+#define _hasAlpha(format) (format==G2D_RGBA8888 || format==G2D_BGRA8888 \
+	|| format==G2D_ARGB8888 || format==G2D_ABGR8888)
+
+
+static int
+g2d_clear_solid(void *handle, struct g2d_surfaceEx *dstG2dSurface, g2dRECT *clipRect, int clcolor)
+{
+	struct g2d_surfaceEx* soildSurface = dstG2dSurface;
+
+	g2d_SetSurfaceRect(soildSurface, clipRect);
+	soildSurface->base.clrcolor = clcolor;
+
+	if(g2d_clear(handle,  &soildSurface->base)){
+		printG2dSurfaceInfo(dstG2dSurface, "SOILD DST:");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+g2d_blit_surface(void *handle, struct g2d_surfaceEx * srcG2dSurface, struct g2d_surfaceEx *dstG2dSurface,
+	g2dRECT *srcRect, g2dRECT *dstRect)
+{
+	g2d_SetSurfaceRect(srcG2dSurface, srcRect);
+	g2d_SetSurfaceRect(dstG2dSurface, dstRect);
+	srcG2dSurface->base.blendfunc = G2D_ONE;
+	dstG2dSurface->base.blendfunc = G2D_ONE_MINUS_SRC_ALPHA;
+	if(!(_hasAlpha(srcG2dSurface->base.format))){
+		g2d_disable(handle, G2D_BLEND);
+	}
+
+	if(g2d_blitEx(handle, srcG2dSurface, dstG2dSurface)){
+		printG2dSurfaceInfo(srcG2dSurface, "SRC:");
+		printG2dSurfaceInfo(dstG2dSurface, "DST:");
+		return -1;
+	}
+	return 0;
+}
+
+static void
+g2d_clip_rects(enum g2d_rotation transform,
+			g2dRECT *srcRect,
+			g2dRECT *dstrect,
+			int dstWidth,
+			int dstHeight)
+{
+	int srcWidth = srcRect->right - srcRect->left;
+	int srcHeight = srcRect->bottom - srcRect->top;
+	float scale_v = 1.0f;
+	float scale_h = 1.0f;
+
+	if(transform == G2D_ROTATION_90
+		|| transform == G2D_ROTATION_270)
+	{
+		scale_h = (float)srcHeight / (dstrect->right - dstrect->left);
+		scale_v = (float)srcWidth / (dstrect->bottom - dstrect->top);
+	}
+	else
+	{
+		scale_h = (float)srcWidth / (dstrect->right - dstrect->left);
+		scale_v = (float)srcHeight / (dstrect->bottom - dstrect->top);
+	}
+	switch (transform) {
+	case G2D_ROTATION_0:
+		if(dstrect->left < 0)
+		{
+			srcRect->left += floorf((float)(-dstrect->left) * scale_h);
+			dstrect->left = 0;
+			if(srcRect->left >= srcRect->right)
+				return;
+		}
+		if(dstrect->right > dstWidth)
+		{
+			srcRect->right -= floorf((float)(dstrect->right - dstWidth) * scale_h);
+			dstrect->right = dstWidth;
+			if(srcRect->right <= srcRect->left)
+				return;
+		}
+		if(dstrect->top < 0)
+		{
+			srcRect->top += floorf((float)(-dstrect->top) * scale_v);
+			dstrect->top = 0;
+			if(srcRect->top >= srcRect->bottom)
+				return;
+		}
+		if(dstrect->bottom > dstHeight)
+		{
+			srcRect->bottom -= floorf((float)(dstrect->bottom - dstHeight) * scale_v);
+			dstrect->bottom = dstHeight;
+			if(srcRect->bottom < 0)
+				return;
+		}
+		break;
+	case G2D_ROTATION_270:
+		if(dstrect->left < 0)
+		{
+			srcRect->bottom -= floorf((float)(-dstrect->left) * scale_h);
+			dstrect->left = 0;
+			if(srcRect->top >= srcRect->bottom)
+					return;
+		}
+		if(dstrect->bottom > dstHeight)
+		{
+			srcRect->right -= floorf((float)(dstrect->bottom - dstHeight) * scale_v);
+			dstrect->bottom = dstHeight;
+			if(srcRect->right < 0)
+				return;
+		}
+		if(dstrect->top < 0)
+		{
+			srcRect->left += floorf((float)(-dstrect->top) * scale_v);
+			dstrect->top = 0;
+			if(srcRect->left > srcRect->right)
+				return;
+		}
+		if(dstrect->right > dstWidth) {
+			srcRect->top += floorf((float)(dstrect->right - dstWidth) * scale_h);
+			dstrect->right = dstWidth;
+			if(srcRect->top >= srcRect->bottom)
+				return;
+		}
+		break;
+	case G2D_ROTATION_90:
+		if(dstrect->left < 0)
+		{
+			srcRect->top += floorf((float)(-dstrect->left) * scale_h);
+			dstrect->left = 0;
+			if(srcRect->top >= srcRect->bottom)
+					return;
+		}
+		if(dstrect->top < 0)
+		{
+			srcRect->right -= floorf((float)(-dstrect->top) * scale_v);
+			dstrect->top = 0;
+			if(srcRect->left >= srcRect->right)
+				return;
+		}
+		if(dstrect->bottom > dstHeight)
+		{
+			srcRect->left += floorf((float)(dstrect->bottom - dstHeight) * scale_v);
+			dstrect->bottom = dstHeight;
+			if(srcRect->right <= srcRect->left)
+				return;
+		}
+		if(dstrect->right > dstWidth)
+		{
+			srcRect->bottom -= floorf((float)(dstrect->right - dstWidth) * scale_h);
+			dstrect->right = dstWidth;
+			if(srcRect->bottom <= srcRect->top)
+				return;
+		}
+		break;
+	case G2D_ROTATION_180:
+		if(dstrect->left < 0)
+		{
+			srcRect->right -= floorf((float)(-dstrect->left) * scale_h);
+			dstrect->left = 0;
+			if(srcRect->left >= srcRect->right)
+					return;
+		}
+		if(dstrect->right > dstWidth)
+		{
+			srcRect->left += floorf((float)(dstrect->right - dstWidth) * scale_h);
+			dstrect->right = dstWidth;
+			if(srcRect->right <= srcRect->left)
+				return;
+		}
+		if(dstrect->top < 0)
+		{
+			srcRect->bottom -= floorf((float)(-dstrect->top) * scale_v);
+			dstrect->top = 0;
+			if(srcRect->top >= srcRect->bottom)
+				return;
+		}
+		if(dstrect->bottom > dstHeight) {
+			srcRect->top += floorf((float)(dstrect->bottom - dstHeight) * scale_v);
+			dstrect->bottom = dstHeight;
+			if(srcRect->top >= srcRect->bottom)
+				return;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static int
+g2d_renderer_read_pixels(struct weston_output *output,
+				   const struct pixel_format_info *format, void *pixels,
+				   uint32_t x, uint32_t y,
+				   uint32_t width, uint32_t height)
+{
+	struct g2d_surfaceEx  dstSurface;
+	struct g2d_surfaceEx  *srcSurface;
+	struct g2d_output_state *go = get_output_state(output);
+	struct g2d_renderer *gr = get_renderer(output->compositor);
+	struct g2d_buf *read_buf = NULL;
+	enum g2d_format dst_format;
+	g2dRECT	srcRect  = {x, y, x + width, y + height};
+	g2dRECT dstRect  = {0, 0, width, height};
+
+	if( g2d_getG2dFormat_from_pixman(format->pixman_format, &dst_format))
+		return -1;
+
+	read_buf = g2d_alloc(width * height * 4, 0);
+	if( !read_buf)
+		return -1;
+
+	srcSurface = go->drm_hw_buffer;
+
+	dstSurface.base.planes[0] = read_buf->buf_paddr;
+	dstSurface.base.format = dst_format;
+	dstSurface.base.width  = width;
+	dstSurface.base.height = height;
+	dstSurface.base.stride = width;
+	dstSurface.base.rot    = G2D_FLIP_V;
+	if(g2d_blit_surface(gr->handle, srcSurface, &dstSurface, &srcRect, &dstRect)) {
+		g2d_free(read_buf);
+		return -1;
+	}
+	g2d_finish(gr->handle);
+
+	memcpy(pixels, read_buf->buf_vaddr, width * height * PIXMAN_FORMAT_BPP(format->pixman_format)/8);
+	g2d_free(read_buf);
+
+	return 0;
+}
+
+static int g2d_int_from_double(double d)
+{
+	return wl_fixed_to_int(wl_fixed_from_double(d));
+}
+
+static void
+repaint_region(struct weston_view *ev, struct weston_output *output, struct g2d_output_state *go, pixman_region32_t *region,
+		pixman_region32_t *surf_region){
+
+	struct g2d_renderer *gr = get_renderer(ev->surface->compositor);
+	struct g2d_surface_state *gs = get_surface_state(ev->surface);
+	struct weston_buffer *buffer = gs->buffer_ref.buffer;
+
+	pixman_box32_t *rects, *surf_rects, *bb_rects;
+	int i, j, nrects, nsurf, nbb=0;
+	g2dRECT srcRect = {0};
+	g2dRECT dstrect = {0};
+	g2dRECT clipRect = {0};
+	int dstWidth = 0;
+	int dstHeight = 0;
+	struct g2d_surfaceEx *dstsurface = go->drm_hw_buffer;
+	struct g2d_surfaceEx srcsurface = gs->g2d_surface;
+	uint32_t view_transform = ev->surface->buffer_viewport.buffer.transform;
+	int src_x = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_x);
+	int src_y = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_y);
+	int width = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_width);
+	int height = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_height);
+	int src_width = -1;
+	int src_height = -1;
+	int scale = ev->surface->buffer_viewport.buffer.scale;
+	if (ev->alpha < 1.0) {
+		/* Skip the render for global alpha, a workaround to disable the
+		   fade effect, it created garbage info in the sequence test.*/
+		return;
+	}
+
+	if (!gs->solid_clear) {
+		if (srcsurface.base.width <= 0 || srcsurface.base.height <= 0) {
+			return;
+		}
+	}
+
+	bb_rects = pixman_region32_rectangles(&ev->transform.boundingbox, &nbb);
+
+	if(!gs->attached || nbb <= 0)
+	{
+		return;
+	}
+
+	convert_size_by_view_transform(&src_width, &src_height, width, height, view_transform);
+
+	rects = pixman_region32_rectangles(region, &nrects);
+	surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
+	if(src_width != -1 && src_width > 0 && src_x >=0 && src_y >= 0
+		&& src_x < gs->g2d_surface.base.width
+		&& src_y < gs->g2d_surface.base.height)
+	{
+		srcRect.left = src_x * scale;
+		srcRect.top = src_y * scale;
+		srcRect.right = min (gs->g2d_surface.base.width, (src_x + src_width) * scale);
+		srcRect.bottom = min (gs->g2d_surface.base.height, (src_y + src_height) * scale);
+	}
+	else
+	{
+		srcRect.left = srcsurface.base.left;
+		srcRect.top  = srcsurface.base.top;
+		srcRect.right  = srcsurface.base.right;
+		srcRect.bottom = srcsurface.base.bottom;
+	}
+
+	dstWidth  = dstsurface->base.width;
+	dstHeight = dstsurface->base.height;
+	/*Calculate the destrect once for all*/
+	dstrect.left = bb_rects[0].x1;
+	dstrect.top = bb_rects[0].y1;
+	dstrect.right = bb_rects[0].x2;
+	dstrect.bottom = bb_rects[0].y2;
+	/*Multi display support*/
+	if(output->x > 0)
+	{
+		dstrect.left = dstrect.left - output->x;
+		dstrect.right = dstrect.right - output->x;
+	}
+
+	calculate_rect_with_transform(dstsurface->base.width,
+					  dstsurface->base.height,
+					  output->transform, &dstrect);
+
+	/* Calculate the angle at which the frame buffer really needs to be rotated based
+	 * on the rotation angle of the output and the angle set by the client.
+	 */
+	srcsurface.base.rot = convert_transform_to_rot(view_transform, output->transform);
+	g2d_clip_rects(srcsurface.base.rot, &srcRect, &dstrect, dstWidth, dstHeight);
+
+	for (i = 0; i < nrects; i++)
+	{
+		pixman_box32_t *rect = &rects[i];
+		float min_x, max_x, min_y, max_y;
+
+		for (j = 0; j < nsurf; j++)
+		{
+			pixman_box32_t *surf_rect = &surf_rects[j];
+			struct weston_coord e[8];      /* edge points in screen space */
+			int n;
+			int m=0;
+			n = calculate_edges(ev, rect, surf_rect, e);
+			if (n < 3)
+				continue;
+
+			min_x = max_x = e[0].x;
+			min_y = max_y = e[0].y;
+			for (m = 1; m < n; m++)
+			{
+				min_x = min(min_x, e[m].x);
+				max_x = max(max_x, e[m].x);
+				min_y = min(min_y, e[m].y);
+				max_y = max(max_y, e[m].y);
+			}
+
+			clipRect.left = g2d_int_from_double(min_x);
+			clipRect.top = g2d_int_from_double(min_y);
+			clipRect.right = g2d_int_from_double(max_x);
+			clipRect.bottom = g2d_int_from_double(max_y);
+
+			if(output->x > 0)
+			{
+				clipRect.left = clipRect.left - output->x;
+				clipRect.right = clipRect.right - output->x;
+			}
+			/* Need compute the clip rect with transform */
+			calculate_rect_with_transform(dstsurface->base.width,
+							  dstsurface->base.height,
+							  output->transform, &clipRect);
+			if(clipRect.left >= clipRect.right || clipRect.top >= clipRect.bottom)
+			{
+				return;
+			}
+			g2d_set_clipping(gr->handle, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+			/* g2d_clear can't clear the sloid buffer with alpha.*/
+			if (gs->solid_clear &&
+			    buffer->type == WESTON_BUFFER_SOLID &&
+			    buffer->pixel_format->format !=DRM_FORMAT_ARGB8888) {
+				g2d_clear_solid(gr->handle, dstsurface, &clipRect, gs->clcolor);
+			}
+			else
+			{
+				g2d_blit_surface(gr->handle, &srcsurface, dstsurface, &srcRect, &dstrect);
+			}
+
+		}
+	}
+}
+
+static int sync_wait(int fd, int timeout)
+{
+    struct pollfd fds;
+    int ret;
+
+    if (fd < 0) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    fds.fd = fd;
+    fds.events = POLLIN;
+
+    do {
+        ret = poll(&fds, 1, timeout);
+        if (ret > 0) {
+            if (fds.revents & (POLLERR | POLLNVAL)) {
+                errno = EINVAL;
+                return -1;
+            }
+            return 0;
+        } else if (ret == 0) {
+            errno = ETIME;
+            return -1;
+        }
+    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+    return ret;
+}
+
+static int
+ensure_surface_buffer_is_ready(struct g2d_renderer *gr,
+			       struct g2d_surface_state *gs)
+{
+	int ret = 0;
+	struct weston_surface *surface = gs->surface;
+	struct weston_buffer *buffer = gs->buffer_ref.buffer;
+
+	if (!buffer)
+		return 0;
+
+	if(buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) {
+		if (!buffer->resource)
+			return 0;
+
+		/*Update vivBuffer and set g2d surface */
+		struct wl_viv_buffer *vivBuffer = wl_resource_get_user_data(buffer->resource);
+
+		if (gr->update_buffer)
+			gr->update_buffer(gr->egl_display, (void *)buffer->resource, EGL_WAYLAND_BUFFER_WL);
+
+		ret = get_g2dSurface(vivBuffer, &gs->g2d_surface);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	if (surface->acquire_fence_fd < 0)
+		return 0;
+
+	ret = sync_wait(surface->acquire_fence_fd, 2000);
+
+	if (ret < 0 && errno == ETIME){
+		/* Print a warning. */
+		weston_log("%s: Warning: wait for fence fd=%d", __func__, surface->acquire_fence_fd);
+
+		/* Wait for ever. */
+		ret = sync_wait(surface->acquire_fence_fd, -1);
+	}
+
+	return ret;
+}
+
+static bool
+g2d_renderer_do_capture(struct weston_output *output, struct weston_buffer *into,
+		       const struct weston_geometry *rect)
+{
+	struct wl_shm_buffer *shm = into->shm_buffer;
+	const struct pixel_format_info *fmt = into->pixel_format;
+	void *shm_pixels;
+	void *read_target;
+	int32_t stride;
+	pixman_image_t *tmp = NULL;
+
+	assert(into->type == WESTON_BUFFER_SHM);
+	assert(shm);
+
+	stride = wl_shm_buffer_get_stride(shm);
+	if (stride % 4 != 0)
+		return false;
+
+	shm_pixels = wl_shm_buffer_get_data(shm);
+
+	tmp = pixman_image_create_bits(fmt->pixman_format,
+					   rect->width, rect->height,
+					   NULL, 0);
+	if (!tmp)
+		return false;
+
+	read_target = pixman_image_get_data(tmp);
+
+	wl_shm_buffer_begin_access(shm);
+
+	g2d_renderer_read_pixels(output, fmt, read_target, rect->x, rect->y, rect->width, rect->height);
+
+	if (tmp) {
+		pixman_image_t *shm_image;
+		pixman_transform_t flip;
+
+		shm_image = pixman_image_create_bits_no_clear(fmt->pixman_format,
+							      rect->width,
+							      rect->height,
+							      shm_pixels,
+							      stride);
+		abort_oom_if_null(shm_image);
+
+		pixman_transform_init_scale(&flip, pixman_fixed_1,
+					    pixman_fixed_minus_1);
+		pixman_transform_translate(&flip, NULL,	0,
+					   pixman_int_to_fixed(rect->height));
+		pixman_image_set_transform(tmp, &flip);
+
+		pixman_image_composite32(PIXMAN_OP_SRC,
+					 tmp,       /* src */
+					 NULL,      /* mask */
+					 shm_image, /* dest */
+					 0, 0,      /* src x,y */
+					 0, 0,      /* mask x,y */
+					 0, 0,      /* dest x,y */
+					 rect->width, rect->height);
+
+		pixman_image_unref(shm_image);
+		pixman_image_unref(tmp);
+	}
+
+	wl_shm_buffer_end_access(shm);
+
+	return true;
+}
+
+static void
+g2d_renderer_do_capture_tasks(struct weston_output *output,
+			     enum weston_output_capture_source source)
+{
+	struct g2d_output_state *go = get_output_state(output);
+	const struct pixel_format_info *format;
+	struct weston_capture_task *ct;
+	struct weston_geometry rect;
+
+	switch (source) {
+	case WESTON_OUTPUT_CAPTURE_SOURCE_FRAMEBUFFER:
+		format = output->compositor->read_format;
+		rect = go->area;
+		rect.y = go->fb_size.height - go->area.y - go->area.height;
+		break;
+	case WESTON_OUTPUT_CAPTURE_SOURCE_FULL_FRAMEBUFFER:
+		format = output->compositor->read_format;
+		rect.x = 0;
+		rect.y = 0;
+		rect.width = go->fb_size.width;
+		rect.height = go->fb_size.height;
+		break;
+	default:
+		assert(0);
+		return;
+	}
+
+	while ((ct = weston_output_pull_capture_task(output, source, rect.width,
+						     rect.height, format))) {
+		struct weston_buffer *buffer = weston_capture_task_get_buffer(ct);
+
+		assert(buffer->width == rect.width);
+		assert(buffer->height == rect.height);
+		assert(buffer->pixel_format->format == format->format);
+
+		if (buffer->type != WESTON_BUFFER_SHM ||
+		    buffer->buffer_origin != ORIGIN_TOP_LEFT) {
+			weston_capture_task_retire_failed(ct, "G2D: unsupported buffer");
+			continue;
+		}
+
+		if (g2d_renderer_do_capture(output, buffer, &rect))
+			weston_capture_task_retire_complete(ct);
+		else
+			weston_capture_task_retire_failed(ct, "G2D: capture failed");
+	}
+}
+
+static void
+draw_view(struct weston_view *ev, struct weston_output *output,
+		 pixman_region32_t *damage) /* in global coordinates */
+{
+	struct weston_compositor *ec = ev->surface->compositor;
+	struct g2d_output_state *go = get_output_state(output);
+	struct g2d_surface_state *gs = get_surface_state(ev->surface);
+	struct g2d_renderer *gr = get_renderer(ec);
+	/* repaint bounding region in global coordinates: */
+	pixman_region32_t repaint;
+	/* opaque region in surface coordinates: */
+	pixman_region32_t surface_opaque;
+	/* non-opaque region in surface coordinates: */
+	pixman_region32_t surface_blend;
+
+	pixman_region32_init(&repaint);
+	pixman_region32_intersect(&repaint,
+				  &ev->transform.boundingbox, damage);
+	pixman_region32_subtract(&repaint, &repaint, &ev->clip);
+
+	if (!pixman_region32_not_empty(&repaint))
+		goto out;
+
+	if (ensure_surface_buffer_is_ready(gr, gs) < 0)
+		goto out;
+
+	/* blended region is whole surface minus opaque region: */
+	pixman_region32_init_rect(&surface_blend, 0, 0,
+				  ev->surface->width, ev->surface->height);
+	if (ev->geometry.scissor_enabled)
+		pixman_region32_intersect(&surface_blend, &surface_blend,
+					  &ev->geometry.scissor);
+	pixman_region32_subtract(&surface_blend, &surface_blend,
+				 &ev->surface->opaque);
+
+	/* XXX: Should we be using ev->transform.opaque here? */
+	pixman_region32_init(&surface_opaque);
+	if (ev->geometry.scissor_enabled)
+		pixman_region32_intersect(&surface_opaque,
+					  &ev->surface->opaque,
+					  &ev->geometry.scissor);
+	else
+		pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
+
+	if (pixman_region32_not_empty(&surface_opaque)) {
+		if (ev->alpha < 1.0) {
+			g2d_enable(gr->handle, G2D_BLEND);
+			g2d_enable(gr->handle, G2D_GLOBAL_ALPHA);
+			gs->g2d_surface.base.global_alpha = ev->alpha * 0xFF;
+		}
+		repaint_region(ev, output, go, &repaint, &surface_opaque);
+		g2d_disable(gr->handle, G2D_GLOBAL_ALPHA);
+		g2d_disable(gr->handle, G2D_BLEND);
+	}
+
+	if (pixman_region32_not_empty(&surface_blend)) {
+		g2d_enable(gr->handle, G2D_BLEND);
+		if (ev->alpha < 1.0) {
+			g2d_enable(gr->handle, G2D_GLOBAL_ALPHA);
+			gs->g2d_surface.base.global_alpha = ev->alpha * 0xFF;
+		}
+		repaint_region(ev, output, go, &repaint, &surface_blend);
+		g2d_disable(gr->handle, G2D_GLOBAL_ALPHA);
+		g2d_disable(gr->handle, G2D_BLEND);
+	}
+	pixman_region32_fini(&surface_blend);
+	pixman_region32_fini(&surface_opaque);
+
+out:
+	pixman_region32_fini(&repaint);
+}
+
+static void
+repaint_views(struct weston_output *output, pixman_region32_t *damage)
+{
+	struct weston_compositor *compositor = output->compositor;
+	struct weston_view *view;
+
+	wl_list_for_each_reverse(view, &compositor->view_list, link)
+		if (view->plane == &compositor->primary_plane)
+			draw_view(view, output, damage);
+}
+
+static void
+output_get_damage(struct weston_output *output,
+		  pixman_region32_t *buffer_damage)
+{
+	struct g2d_output_state *go = get_output_state(output);
+	int i;
+
+	for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
+		pixman_region32_union(buffer_damage,
+			buffer_damage,
+			&go->buffer_damage[i]);
+}
+
+static void
+output_rotate_damage(struct weston_output *output,
+			 pixman_region32_t *output_damage)
+{
+	struct g2d_output_state *go = get_output_state(output);
+
+	go->current_buffer = (go->current_buffer + 1) % BUFFER_DAMAGE_COUNT;
+
+	pixman_region32_copy(&go->buffer_damage[go->current_buffer], output_damage);
+}
+
+#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
+static void
+g2d_update_buffer_release_fences(struct weston_compositor *compositor,
+			     int fence_fd)
+{
+	struct weston_view *view;
+
+	wl_list_for_each_reverse(view, &compositor->view_list, link) {
+		struct g2d_surface_state *gs;
+		struct weston_buffer_release *buffer_release;
+
+		if (view->plane != &compositor->primary_plane)
+			continue;
+
+		gs = get_surface_state(view->surface);
+		buffer_release = gs->buffer_release_ref.buffer_release;
+
+		if(!buffer_release) {
+			continue;
+		}
+
+		/* If we have a buffer_release then it means we support fences,
+		 * and we should be able to create the release fence. If we
+		 * can't, something has gone horribly wrong, so disconnect the
+		 * client.
+		 */
+		if (fence_fd == -1) {
+			fd_clear(&buffer_release->fence_fd);
+			continue;
+		}
+
+		fd_update(&buffer_release->fence_fd, dup(fence_fd));
+	}
+}
+#endif
+
+static void
+g2d_renderer_repaint_output(struct weston_output *output,
+				 pixman_region32_t *output_damage,
+				 struct weston_renderbuffer *renderbuffer)
+{
+	struct weston_compositor *compositor = output->compositor;
+	struct g2d_renderer *gr = get_renderer(compositor);
+	pixman_region32_t buffer_damage, total_damage;
+#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
+	struct g2d_output_state *go = get_output_state(output);
+#endif
+	int fence_fd = -1;
+
+	pixman_region32_init(&total_damage);
+	pixman_region32_init(&buffer_damage);
+
+	output_get_damage(output, &buffer_damage);
+	output_rotate_damage(output, output_damage);
+	pixman_region32_union(&total_damage, &buffer_damage, output_damage);
+
+	repaint_views(output, &total_damage);
+
+	pixman_region32_fini(&total_damage);
+	pixman_region32_fini(&buffer_damage);
+
+	g2d_renderer_do_capture_tasks(output,
+				     WESTON_OUTPUT_CAPTURE_SOURCE_FRAMEBUFFER);
+	g2d_renderer_do_capture_tasks(output,
+				     WESTON_OUTPUT_CAPTURE_SOURCE_FULL_FRAMEBUFFER);
+
+#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
+	fence_fd = g2d_create_fence_fd(gr->handle);
+	g2d_update_buffer_release_fences(compositor, fence_fd);
+
+	fd_clear(&go->drm_hw_buffer->reserved[0]);
+	go->drm_hw_buffer->reserved[0] = fence_fd;
+#endif
+
+	if(fence_fd == -1)
+		g2d_finish(gr->handle);
+
+	wl_signal_emit(&output->frame_signal, output_damage);
+}
+
+static bool
+g2d_renderer_fill_buffer_info(struct weston_compositor *ec,
+			     struct weston_buffer *buffer)
+{
+	struct g2d_renderer *gr = get_renderer(ec);
+	EGLint format;
+	uint32_t fourcc;
+	bool ret = true;
+
+	buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
+	ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
+			        EGL_WIDTH, &buffer->width);
+	ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
+				EGL_HEIGHT, &buffer->height);
+	ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
+				EGL_TEXTURE_FORMAT, &format);
+	if (!ret) {
+		weston_log("eglQueryWaylandBufferWL failed\n");
+		goto err_free;
+	}
+
+	/* The legacy EGL buffer interface only describes the channels we can
+	 * sample from; not their depths or order. Take a stab at something
+	 * which might be representative. Pessimise extremely hard for
+	 * TEXTURE_EXTERNAL_OES. */
+	switch (format) {
+	case EGL_TEXTURE_RGB:
+		fourcc = DRM_FORMAT_XRGB8888;
+		break;
+	case EGL_TEXTURE_RGBA:
+		fourcc = DRM_FORMAT_ARGB8888;
+		break;
+	case EGL_TEXTURE_EXTERNAL_WL:
+		fourcc = DRM_FORMAT_ARGB8888;
+		break;
+	case EGL_TEXTURE_Y_XUXV_WL:
+		fourcc = DRM_FORMAT_YUYV;
+		break;
+	case EGL_TEXTURE_Y_UV_WL:
+		fourcc = DRM_FORMAT_NV12;
+		break;
+	case EGL_TEXTURE_Y_U_V_WL:
+		fourcc = DRM_FORMAT_YUV420;
+		break;
+	default:
+		assert(0 && "not reached");
+	}
+
+	buffer->pixel_format = pixel_format_get_info(fourcc);
+	assert(buffer->pixel_format);
+	buffer->format_modifier = DRM_FORMAT_MOD_LINEAR;
+
+	return true;
+
+err_free:
+	return false;
+
+}
+
+static void
+g2d_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer)
+{
+	struct wl_viv_buffer *vivBuffer = wl_resource_get_user_data(buffer->resource);
+	buffer->width = vivBuffer->width;
+	buffer->height = vivBuffer->height;
+}
+
+static void
+g2d_renderer_copy_shm_buffer(struct g2d_surface_state *gs, struct weston_buffer *buffer)
+{
+	int alignedWidth = ALIGN_TO_16(buffer->width);
+	int height = 0;
+	uint8_t *src = wl_shm_buffer_get_data(buffer->shm_buffer);
+	uint8_t *dst = gs->shm_buf->buf_vaddr;
+	int bpp = gs->bpp;
+	int plane_size[3] = {0,};
+	int src_plane_offset[3] = {0,};
+	int dst_plane_offset[3] = {0,};
+	int uv_src_stride = 0;
+	int uv_dst_stride = 0;
+	int n_planes = 0;
+	int i, j;
+
+	switch (wl_shm_buffer_get_format(buffer->shm_buffer)) {
+		case WL_SHM_FORMAT_XRGB8888:
+		case WL_SHM_FORMAT_ARGB8888:
+		case WL_SHM_FORMAT_RGB565:
+			n_planes = 1;
+			height = buffer->height;
+			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
+			break;
+		case WL_SHM_FORMAT_YUYV:
+			n_planes = 1;
+			height = ALIGN_TO_16(buffer->height);
+			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
+			break;
+		case WL_SHM_FORMAT_NV12:
+			n_planes = 2;
+			height = ALIGN_TO_16(buffer->height);
+			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
+			plane_size[1] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height / 2;
+			src_plane_offset[1] = plane_size[0];
+			dst_plane_offset[1] = alignedWidth * height;
+			uv_src_stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+			uv_dst_stride = alignedWidth;
+			break;
+		case WL_SHM_FORMAT_YUV420:
+			n_planes = 3;
+			height = ALIGN_TO_16(buffer->height);
+			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
+			plane_size[1] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height / 4;
+			plane_size[2] = plane_size[1];
+			src_plane_offset[1] = plane_size[0];
+			src_plane_offset[2] = plane_size[0] + plane_size[1];
+			dst_plane_offset[1] = alignedWidth * height;
+			dst_plane_offset[2] = dst_plane_offset[1] + alignedWidth * height / 4;
+			uv_src_stride = wl_shm_buffer_get_stride(buffer->shm_buffer) / 2;
+			uv_dst_stride = alignedWidth / 2;
+			break;
+		default:
+			weston_log("warning: copy shm buffer meet unknown format: %08x\n",
+				   wl_shm_buffer_get_format(buffer->shm_buffer));
+			return;
+	}
+
+	wl_shm_buffer_begin_access(buffer->shm_buffer);
+	if(alignedWidth == buffer->width && height == buffer->height)
+	{
+		for (i = 0; i < n_planes; i++)
+			memcpy (dst + dst_plane_offset[i], src + src_plane_offset[i], plane_size[i]);
+	}
+	else
+	{
+		int src_stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+		int dst_stride = alignedWidth * bpp;
+		/* copy the 1st plane */
+		for (i = 0; i < buffer->height; i++)
+		{
+			memcpy(dst + dst_plane_offset[0] + dst_stride * i, src + src_plane_offset[0] + src_stride * i, src_stride);
+		}
+		/* copy the rest plane */
+		for (i = 1; i < n_planes; i++)
+		{
+			for (j = 0; j < buffer->height / 2; j++)
+			{
+				memcpy(dst + dst_plane_offset[i] + uv_dst_stride * j, src + src_plane_offset[i] + uv_src_stride * j, uv_src_stride);
+			}
+		}
+	}
+	wl_shm_buffer_end_access(buffer->shm_buffer);
+}
+
+static void
+g2d_renderer_flush_damage(struct weston_surface *surface,
+			 struct weston_buffer *buffer)
+{
+	struct g2d_surface_state *gs = get_surface_state(surface);
+	struct weston_view *view;
+	int texture_used;
+	pixman_region32_union(&gs->texture_damage,
+				  &gs->texture_damage, &surface->damage);
+
+	if (!buffer)
+		return;
+
+	texture_used = 0;
+	wl_list_for_each(view, &surface->views, surface_link) {
+		if (view->plane == &surface->compositor->primary_plane) {
+			texture_used = 1;
+			break;
+		}
+	}
+	if (!texture_used)
+		return;
+
+	if (!pixman_region32_not_empty(&gs->texture_damage))
+		goto done;
+
+	if(wl_shm_buffer_get(buffer->resource))
+	{
+		g2d_renderer_copy_shm_buffer(gs, buffer);
+	}
+
+done:
+	pixman_region32_fini(&gs->texture_damage);
+	pixman_region32_init(&gs->texture_damage);
+
+	weston_buffer_reference(&gs->buffer_ref, NULL, BUFFER_WILL_NOT_BE_ACCESSED);
+	weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
+}
+
+static uint32_t
+pack_color(const uint32_t format, float *c)
+{
+	uint8_t r = round(c[0] * 255.0f);
+	uint8_t g = round(c[1] * 255.0f);
+	uint8_t b = round(c[2] * 255.0f);
+	uint8_t a = round(c[3] * 255.0f);
+
+	switch (format) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		return (a << 24) | (b << 16) | (g << 8) | r;
+	default:
+		assert(0);
+		return 0;
+	}
+}
+
+static void
+g2d_renderer_attach_solid(struct weston_surface *surface,
+			struct weston_buffer *buffer)
+{
+	struct g2d_surface_state *gs = get_surface_state(surface);
+
+	gs->color[0] = buffer->solid.r;
+	gs->color[1] = buffer->solid.g;
+	gs->color[2] = buffer->solid.b;
+	gs->color[3] = buffer->solid.a;
+	gs->solid_clear = true;
+	gs->clcolor = pack_color(buffer->pixel_format->format, gs->color);
+}
+
+static void
+g2d_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer)
+{
+	struct g2d_surface_state *gs = get_surface_state(es);
+	struct wl_shm_buffer *shm_buffer = buffer->shm_buffer;
+	int buffer_length = 0;
+	int alloc_new_buff = 1;
+	int alignedWidth = 0;
+	int height = 0;
+	enum g2d_format g2dFormat = 0;
+
+	buffer->width = wl_shm_buffer_get_width(shm_buffer);
+	buffer->height = wl_shm_buffer_get_height(shm_buffer);
+	alignedWidth = ALIGN_TO_16(buffer->width);
+
+	switch (wl_shm_buffer_get_format(shm_buffer)) {
+	case WL_SHM_FORMAT_XRGB8888:
+		g2dFormat = G2D_BGRX8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_XBGR8888:
+		g2dFormat = G2D_RGBX8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_BGRX8888:
+		g2dFormat = G2D_XRGB8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_RGBX8888:
+		g2dFormat = G2D_XBGR8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_ARGB8888:
+		g2dFormat = G2D_BGRA8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_ABGR8888:
+		g2dFormat = G2D_RGBA8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_BGRA8888:
+		g2dFormat = G2D_ARGB8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_RGBA8888:
+		g2dFormat = G2D_ABGR8888;
+		gs->bpp = 4;
+		break;
+	case WL_SHM_FORMAT_RGB565:
+		g2dFormat = G2D_RGB565;
+		gs->bpp = 2;
+		break;
+	case WL_SHM_FORMAT_BGR565:
+		g2dFormat = G2D_BGR565;
+		gs->bpp = 2;
+		break;
+	case WL_SHM_FORMAT_YUYV:
+		g2dFormat = G2D_YUYV;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 2;
+		gs->bpp = 2;
+		break;
+	case WL_SHM_FORMAT_UYVY:
+		g2dFormat = G2D_UYVY;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 2;
+		gs->bpp = 2;
+		break;
+	case WL_SHM_FORMAT_YUV420:
+		g2dFormat = G2D_I420;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 3/2;
+		gs->bpp = 1;
+		break;
+	case WL_SHM_FORMAT_YVU420:
+		g2dFormat = G2D_YV12;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 3/2;
+		gs->bpp = 1;
+		break;
+	case WL_SHM_FORMAT_NV12:
+		g2dFormat = G2D_NV12;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 3/2;
+		gs->bpp = 1;
+		break;
+	case WL_SHM_FORMAT_NV16:
+		g2dFormat = G2D_NV16;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 3/2;
+		gs->bpp = 1;
+		break;
+	case WL_SHM_FORMAT_NV21:
+		g2dFormat = G2D_NV21;
+		height = ALIGN_TO_16(buffer->height);
+		buffer_length = alignedWidth * height * 3/2;
+		gs->bpp = 1;
+		break;
+	default:
+		weston_log("warning: unknown shm buffer format: %08x\n",
+			   wl_shm_buffer_get_format(shm_buffer));
+		return;
+	}
+
+	if (height == 0)
+		height = buffer->height;
+
+	if (buffer_length == 0)
+		buffer_length = alignedWidth * buffer->height * gs->bpp;
+
+	/* Only allocate a new g2d buff if it is larger than existing one.*/
+	gs->shm_buf_length = buffer_length;
+	if(gs->shm_buf && gs->shm_buf->buf_size > buffer_length)
+	{
+		alloc_new_buff = 0;
+	}
+
+	if(alloc_new_buff)
+	{
+		if(gs->shm_buf)
+			g2d_free(gs->shm_buf);
+		gs->shm_buf = g2d_alloc(buffer_length, 0);
+		gs->g2d_surface.base.planes[0] = gs->shm_buf->buf_paddr;
+		gs->g2d_surface.base.planes[1] = gs->g2d_surface.base.planes[0] + alignedWidth * height;
+		gs->g2d_surface.base.planes[2] = gs->g2d_surface.base.planes[1] + alignedWidth * height / 4;
+	}
+
+	gs->g2d_surface.base.left = 0;
+	gs->g2d_surface.base.top  = 0;
+	gs->g2d_surface.base.right	= buffer->width;
+	gs->g2d_surface.base.bottom = buffer->height;
+	gs->g2d_surface.base.stride = alignedWidth;
+	gs->g2d_surface.base.width	= buffer->width;
+	gs->g2d_surface.base.height = height;
+	gs->g2d_surface.base.rot	= G2D_ROTATION_0;
+	gs->g2d_surface.base.clrcolor = 0xFF400000;
+	gs->g2d_surface.tiling = G2D_LINEAR;
+	gs->g2d_surface.base.format = g2dFormat;
+}
+
+static bool
+g2d_renderer_resize_output(struct weston_output *output,
+			  const struct weston_size *fb_size,
+			  const struct weston_geometry *area)
+{
+	struct g2d_output_state *go = get_output_state(output);
+
+	check_compositing_area(fb_size, area);
+
+	go->fb_size = *fb_size;
+	go->area = *area;
+
+	weston_output_update_capture_info(output,
+					  WESTON_OUTPUT_CAPTURE_SOURCE_FRAMEBUFFER,
+					  area->width, area->height,
+					  output->compositor->read_format);
+
+	weston_output_update_capture_info(output,
+					  WESTON_OUTPUT_CAPTURE_SOURCE_FULL_FRAMEBUFFER,
+					  fb_size->width, fb_size->height,
+					  output->compositor->read_format);
+
+	return true;
+}
+
+static void
+g2d_renderer_get_g2dformat_from_dmabuf(uint32_t dmaformat,
+			enum g2d_format *g2dFormat, int *bpp)
+{
+	switch (dmaformat) {
+		case DRM_FORMAT_ARGB8888:
+			*g2dFormat = G2D_BGRA8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_ABGR8888:
+			*g2dFormat = G2D_RGBA8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_BGRA8888:
+			*g2dFormat = G2D_ARGB8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_RGBA8888:
+			*g2dFormat = G2D_ABGR8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_XRGB8888:
+			*g2dFormat = G2D_BGRX8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_XBGR8888:
+			*g2dFormat = G2D_RGBX8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_BGRX8888:
+			*g2dFormat = G2D_XRGB8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_RGBX8888:
+			*g2dFormat = G2D_XBGR8888;
+			*bpp = 4;
+			break;
+		case DRM_FORMAT_RGB565:
+			*g2dFormat = G2D_RGB565;
+			*bpp = 2;
+			break;
+		case DRM_FORMAT_BGR565:
+			*g2dFormat = G2D_BGR565;
+			*bpp = 2;
+			break;
+		case DRM_FORMAT_YUYV:
+			*g2dFormat = G2D_YUYV;
+			*bpp = 2;
+			break;
+		case DRM_FORMAT_UYVY:
+			*g2dFormat = G2D_UYVY;
+			*bpp = 2;
+			break;
+		case DRM_FORMAT_NV12:
+			*g2dFormat = G2D_NV12;
+			*bpp = 1;
+			break;
+		case DRM_FORMAT_NV16:
+			*g2dFormat = G2D_NV16;
+			*bpp = 1;
+			break;
+		case DRM_FORMAT_NV21:
+			*g2dFormat = G2D_NV21;
+			*bpp = 1;
+			break;
+		case DRM_FORMAT_YUV420:
+			*g2dFormat = G2D_I420;
+			*bpp = 1;
+			break;
+		case DRM_FORMAT_YVU420:
+			*g2dFormat = G2D_YV12;
+			*bpp = 1;
+			break;
+		default:
+			*g2dFormat = -1;
+			weston_log("warning: unknown dmabuf buffer format: %08x\n", dmaformat);
+			break;
+	}
+}
+
+static void
+g2d_renderer_attach_dmabuf(struct weston_surface *es, struct  weston_buffer *buffer)
+{
+	struct g2d_surface_state *gs = get_surface_state(es);
+	struct linux_dmabuf_buffer *dmabuf = buffer->dmabuf;
+	int alignedWidth = 0;
+	enum g2d_format g2dFormat;
+	unsigned int *paddr;
+	int i = 0;
+	int bpp = 1;
+
+	buffer->width = dmabuf->attributes.width;
+	buffer->height = dmabuf->attributes.height;
+	if(dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED ||
+	   dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED) {
+		alignedWidth  = ALIGN_TO_64(buffer->width);
+	}
+	g2d_renderer_get_g2dformat_from_dmabuf(dmabuf->attributes.format, &g2dFormat, &bpp);
+
+	if (g2dFormat < 0)
+		return;
+
+	paddr = (unsigned int *)linux_dmabuf_buffer_get_user_data(dmabuf);
+	for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+		gs->g2d_surface.base.planes[i] = paddr[i] + dmabuf->attributes.offset[i];
+	}
+
+	gs->g2d_surface.base.left = 0;
+	gs->g2d_surface.base.top  = 0;
+	gs->g2d_surface.base.right	= buffer->width;
+	gs->g2d_surface.base.bottom = buffer->height;
+	gs->g2d_surface.base.width	= buffer->width;
+	gs->g2d_surface.base.height = buffer->height;
+	gs->g2d_surface.base.rot	= G2D_ROTATION_0;
+	if (dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_AMPHION_TILED) {
+		gs->g2d_surface.base.stride = dmabuf->attributes.stride[0];
+		gs->g2d_surface.tiling = G2D_AMPHION_TILED;
+	} else if(dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED ||
+		      dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED){
+		gs->g2d_surface.base.stride = alignedWidth;
+		gs->g2d_surface.tiling = G2D_SUPERTILED;
+	} else {
+		gs->g2d_surface.base.stride = dmabuf->attributes.stride[0] / bpp;
+		gs->g2d_surface.tiling = G2D_LINEAR;
+	}
+	gs->g2d_surface.base.format = g2dFormat;
+}
+
+static void
+g2d_renderer_query_dmabuf_formats(struct weston_compositor *wc,
+			int **formats, int *num_formats)
+{
+	struct g2d_renderer *gr = get_renderer(wc);
+	int g2d_hardware_available = 0;
+	int num;
+	static const int dma_formats[] = {
+		DRM_FORMAT_ARGB8888,
+		DRM_FORMAT_XRGB8888,
+		DRM_FORMAT_RGB565,
+		DRM_FORMAT_BGR565,
+		DRM_FORMAT_YUYV,
+		DRM_FORMAT_UYVY,
+		DRM_FORMAT_NV12,
+		DRM_FORMAT_NV16,
+		DRM_FORMAT_NV21,
+		DRM_FORMAT_YUV420,
+		DRM_FORMAT_YVU420,
+		DRM_FORMAT_ABGR8888,
+		DRM_FORMAT_BGRA8888,
+		DRM_FORMAT_RGBA8888,
+		DRM_FORMAT_XBGR8888,
+		DRM_FORMAT_BGRX8888,
+		DRM_FORMAT_RGBX8888,
+	};
+
+	g2d_query_hardware(gr->handle, G2D_HARDWARE_PXP, &g2d_hardware_available);
+	num = (g2d_hardware_available == 1) ? 11 : ARRAY_LENGTH(dma_formats);
+	*formats = calloc(num, sizeof(int));
+	memcpy(*formats, dma_formats, num * sizeof(int));
+
+	*num_formats = num;
+}
+
+static void
+g2d_renderer_query_dmabuf_modifiers(struct weston_compositor *wc, int format,
+			uint64_t **modifiers,
+			int *num_modifiers)
+{
+	struct g2d_renderer *gr = get_renderer(wc);
+	int num;
+
+	/*
+	 * Set modifiers with DRM_FORMAT_MOD_LINEAR as default,
+	 * if not support eglQueryDmaBufModifiersEXT.
+	 */
+	if (!gr->has_dmabuf_import_modifiers) {
+		*num_modifiers = 1;
+		*modifiers = calloc(*num_modifiers, sizeof(uint64_t));
+		(*modifiers)[0] = DRM_FORMAT_MOD_LINEAR;
+		return;
+	}
+
+	if (!gr->query_dmabuf_modifiers(gr->egl_display, format, 0, NULL,
+					    NULL, &num) ||
+		num == 0) {
+		*num_modifiers = 0;
+		return;
+	}
+
+	*modifiers = calloc(num, sizeof(uint64_t));
+	if (*modifiers == NULL) {
+		*num_modifiers = 0;
+		return;
+	}
+
+	if (!gr->query_dmabuf_modifiers(gr->egl_display, format,
+				num, *modifiers, NULL, &num)) {
+		*num_modifiers = 0;
+		free(*modifiers);
+		return;
+	}
+
+	*num_modifiers = num;
+}
+
+static void
+free_paddr_buf (struct linux_dmabuf_buffer *buffer)
+{
+	unsigned int * paddr = (unsigned int *)buffer->user_data;
+	if (paddr)
+		free (paddr);
+}
+
+static bool
+g2d_renderer_import_dmabuf(struct weston_compositor *wc,
+			struct linux_dmabuf_buffer *dmabuf)
+{
+	struct g2d_buf *g2dBuf = NULL;
+	enum g2d_format g2dFormat;
+	unsigned int *paddr = NULL;
+	int i = 0;
+	int bpp = 1;
+
+	if (!dmabuf)
+		return false;
+
+	g2d_renderer_get_g2dformat_from_dmabuf(dmabuf->attributes.format, &g2dFormat, &bpp);
+	if (g2dFormat < 0)
+		return false;
+
+	paddr = malloc (sizeof (unsigned int) * dmabuf->attributes.n_planes);
+	if (!paddr)
+		return false;
+
+	for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+		if (g2dBuf)
+			g2d_free(g2dBuf);
+		g2dBuf = g2d_buf_from_fd(dmabuf->attributes.fd[i]);
+		if(!g2dBuf)
+			return false;
+		paddr[i] = g2dBuf->buf_paddr;
+	}
+
+	if(!g2dBuf)
+		return false;
+	else
+		g2d_free(g2dBuf);
+
+	linux_dmabuf_buffer_set_user_data(dmabuf, (void *)paddr, free_paddr_buf);
+
+	return true;
+}
+
+static const struct weston_drm_format_array *
+g2d_renderer_get_supported_formats(struct weston_compositor *ec)
+{
+	struct g2d_renderer *gr = get_renderer(ec);
+
+	return &gr->supported_formats;
+}
+
+static int
+populate_supported_formats(struct weston_compositor *ec,
+			   struct weston_drm_format_array *supported_formats)
+{
+	struct weston_drm_format *fmt;
+	int *formats = NULL;
+	uint64_t *modifiers = NULL;
+	int num_formats, num_modifiers;
+	int i, j;
+	int ret = 0;
+
+	/* Use EGL_EXT_image_dma_buf_import_modifiers to query the
+	 * list of formats/modifiers of the renderer. */
+	g2d_renderer_query_dmabuf_formats(ec, &formats, &num_formats);
+	if (num_formats == 0)
+		return 0;
+
+	for (i = 0; i < num_formats; i++) {
+		fmt = weston_drm_format_array_add_format(supported_formats,
+							 formats[i]);
+		if (!fmt) {
+			ret = -1;
+			goto out;
+		}
+
+		/* Always add DRM_FORMAT_MOD_INVALID, as EGL implementations
+		 * support implicit modifiers. */
+		ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID);
+		if (ret < 0)
+			goto out;
+
+		g2d_renderer_query_dmabuf_modifiers(ec, formats[i],
+						   &modifiers, &num_modifiers);
+		if (num_modifiers == 0)
+			continue;
+
+		for (j = 0; j < num_modifiers; j++) {
+			/* Skip MOD_INVALID, as it has already been added. */
+			if (modifiers[j] == DRM_FORMAT_MOD_INVALID)
+				continue;
+			/* Only add 2D supported modifiers. */
+			if (modifiers[j] == DRM_FORMAT_MOD_LINEAR ||
+			    modifiers[j] == DRM_FORMAT_MOD_AMPHION_TILED ||
+			    modifiers[j] == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED ||
+			    modifiers[j] == DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED) {
+				ret = weston_drm_format_add_modifier(fmt, modifiers[j]);
+				if (ret < 0) {
+					free(modifiers);
+					goto out;
+				}
+			}
+		}
+		free(modifiers);
+	}
+
+out:
+	free(formats);
+	return ret;
+}
+
+static void
+g2d_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+{
+	struct g2d_surface_state *gs = get_surface_state(es);
+	gs->solid_clear = false;
+
+	if (!buffer) {
+		gs->attached = 0;
+		return;
+	}
+
+	switch (buffer->type) {
+	case WESTON_BUFFER_SHM:
+		g2d_renderer_attach_shm(es, buffer);
+		break;
+	case WESTON_BUFFER_DMABUF:
+		g2d_renderer_attach_dmabuf(es, buffer);
+		break;
+	case WESTON_BUFFER_RENDERER_OPAQUE:
+		g2d_renderer_attach_egl(es, buffer);
+		break;
+	case WESTON_BUFFER_SOLID:
+		g2d_renderer_attach_solid(es, buffer);
+		break;
+	default:
+		break;
+	}
+	gs->attached = 1;
+	weston_buffer_reference(&gs->buffer_ref, buffer,
+				BUFFER_MAY_BE_ACCESSED);
+	weston_buffer_release_reference(&gs->buffer_release_ref,
+					es->buffer_release_ref.buffer_release);
+}
+
+static void
+surface_state_destroy(struct g2d_surface_state *gs, struct g2d_renderer *gr)
+{
+	wl_list_remove(&gs->surface_destroy_listener.link);
+	wl_list_remove(&gs->renderer_destroy_listener.link);
+	if(gs->surface)
+		gs->surface->renderer_state = NULL;
+
+	if(gs->shm_buf)
+	{
+		g2d_free(gs->shm_buf);
+		gs->shm_buf = NULL;
+	}
+	if(gs->dma_buf)
+	{
+		g2d_free(gs->dma_buf);
+		gs->dma_buf = NULL;
+	}
+
+	weston_buffer_reference(&gs->buffer_ref, NULL, BUFFER_WILL_NOT_BE_ACCESSED);
+	weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
+	free(gs);
+}
+
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+	struct g2d_surface_state *gs;
+	struct g2d_renderer *gr;
+
+	gs = container_of(listener, struct g2d_surface_state,
+			  surface_destroy_listener);
+
+	gr = get_renderer(gs->surface->compositor);
+	surface_state_destroy(gs, gr);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+	struct g2d_surface_state *gs;
+	struct g2d_renderer *gr;
+
+	gr = data;
+
+	gs = container_of(listener, struct g2d_surface_state,
+			  renderer_destroy_listener);
+
+	surface_state_destroy(gs, gr);
+}
+
+
+static int
+g2d_renderer_create_surface(struct weston_surface *surface)
+{
+	struct g2d_surface_state *gs;
+	struct g2d_renderer *gr = get_renderer(surface->compositor);
+
+	gs = zalloc(sizeof *gs);
+	if (gs == NULL)
+		return -1;
+
+	/* A buffer is never attached to solid color surfaces, yet
+	 * they still go through texcoord computations. Do not divide
+	 * by zero there.
+	 */
+	gs->pitch = 1;
+
+	gs->surface = surface;
+
+	pixman_region32_init(&gs->texture_damage);
+	surface->renderer_state = gs;
+
+	gs->surface_destroy_listener.notify =
+		surface_state_handle_surface_destroy;
+	wl_signal_add(&surface->destroy_signal,
+			  &gs->surface_destroy_listener);
+
+	gs->renderer_destroy_listener.notify =
+		surface_state_handle_renderer_destroy;
+	wl_signal_add(&gr->destroy_signal,
+			  &gs->renderer_destroy_listener);
+
+	if (surface->buffer_ref.buffer) {
+		g2d_renderer_attach(surface, surface->buffer_ref.buffer);
+		if (surface->buffer_ref.buffer->type == WESTON_BUFFER_SHM) {
+			g2d_renderer_flush_damage(surface,
+						 surface->buffer_ref.buffer);
+		}
+	}
+
+	return 0;
+}
+
+/* create use-g2d-renderer */
+static void
+create_g2d_file()
+{
+	char *dir, *path;
+	mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+	dir = getenv("XDG_RUNTIME_DIR");
+	path = malloc(strlen(dir) + 40);
+	strcpy(path, dir);
+	strcat(path, "/use-g2d-renderer");
+	close(open(path, O_CREAT | O_RDWR, mode));
+	free(path);
+}
+
+/* remove use-g2d-renderer */
+static void
+remove_g2d_file()
+{
+	char *dir, *path;
+
+	dir = getenv("XDG_RUNTIME_DIR");
+	path = malloc(strlen(dir) + 40);
+	strcpy(path, dir);
+	strcat(path, "/use-g2d-renderer");
+	remove(path);
+	free(path);
+}
+
+static void
+g2d_renderer_output_destroy(struct weston_output *output)
+{
+	struct g2d_output_state *go = get_output_state(output);
+	int i;
+
+	for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
+	{
+		pixman_region32_fini(&go->buffer_damage[i]);
+	}
+
+#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
+	fd_clear(&go->drm_hw_buffer->reserved[0]);
+#endif
+
+	free(go);
+}
+
+static void
+g2d_renderer_destroy(struct weston_compositor *ec)
+{
+	struct g2d_renderer *gr = get_renderer(ec);
+
+	wl_signal_emit(&gr->destroy_signal, gr);
+	g2d_close(gr->handle);
+#ifdef ENABLE_EGL
+	if(gr->bind_display)
+		gr->unbind_display(gr->egl_display, gr->wl_display);
+	eglTerminate(gr->egl_display);
+#endif
+	free(ec->renderer);
+	ec->renderer = NULL;
+
+	weston_drm_format_array_fini(&gr->supported_formats);
+
+	remove_g2d_file();
+}
+
+static void
+g2d_renderer_set_egl_device(struct g2d_renderer *gr)
+{
+	EGLAttrib attrib;
+	const char *extensions;
+
+	if (!gr->query_display_attrib(gr->egl_display, EGL_DEVICE_EXT, &attrib)) {
+		weston_log("failed to get EGL device\n");
+		return;
+	}
+
+	gr->egl_device = (EGLDeviceEXT) attrib;
+
+	extensions = gr->query_device_string(gr->egl_device, EGL_EXTENSIONS);
+	if (!extensions) {
+		weston_log("failed to get EGL extensions\n");
+		return;
+	}
+
+	/* Try to query the render node using EGL_DRM_RENDER_NODE_FILE_EXT */
+	if (weston_check_egl_extension(extensions, "EGL_EXT_device_drm_render_node"))
+		gr->drm_device = gr->query_device_string(gr->egl_device,
+							 EGL_DRM_RENDER_NODE_FILE_EXT);
+
+	/* The extension is not supported by the Mesa version of the system or
+	 * the query failed. Fallback to EGL_DRM_DEVICE_FILE_EXT */
+	if (!gr->drm_device && weston_check_egl_extension(extensions, "EGL_EXT_device_drm"))
+		gr->drm_device = gr->query_device_string(gr->egl_device,
+							 EGL_DRM_DEVICE_FILE_EXT);
+
+	if (!gr->drm_device)
+		weston_log("failed to query DRM device from EGL\n");
+}
+
+static int
+g2d_renderer_setup_egl_display(struct g2d_renderer *gr,
+			      void *native_window)
+{
+	gr->egl_display = NULL;
+
+	if(get_platform_display)
+		gr->egl_display = get_platform_display(EGL_PLATFORM_GBM_KHR,
+				native_window, NULL);
+
+	if (!gr->egl_display) {
+		weston_log("failed to create display\n");
+		return -1;
+	}
+
+	if (!eglInitialize(gr->egl_display, NULL, NULL)) {
+		weston_log("failed to initialize display\n");
+		return -1;
+	}
+
+	if (gr->has_device_query)
+		g2d_renderer_set_egl_device(gr);
+
+	return 0;
+}
+
+static int
+g2d_renderer_setup_egl_client_extensions(struct g2d_renderer *gr)
+{
+	const char *extensions;
+
+	extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+	if (!extensions) {
+		weston_log("Retrieving EGL client extension string failed.\n");
+		return -1;
+	}
+
+	if (weston_check_egl_extension(extensions, "EGL_EXT_device_query")) {
+		gr->query_display_attrib =
+			(void *) eglGetProcAddress("eglQueryDisplayAttribEXT");
+		gr->query_device_string =
+			(void *) eglGetProcAddress("eglQueryDeviceStringEXT");
+		gr->has_device_query = true;
+	}
+
+	return 0;
+}
+
+static int
+g2d_renderer_setup_egl_extensions(struct g2d_renderer *gr)
+{
+	const char *extensions;
+	int ret;
+
+	extensions =
+		(const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
+	if (!extensions) {
+		weston_log("Retrieving EGL extension string failed.\n");
+		return -1;
+	}
+
+	if (weston_check_egl_extension(extensions, "EGL_WL_bind_wayland_display"))
+		gr->has_bind_display = true;
+	if (gr->has_bind_display) {
+		assert(gr->bind_display);
+		assert(gr->unbind_display);
+		assert(gr->query_buffer);
+		ret = gr->bind_display(gr->egl_display, gr->wl_display);
+		if (!ret)
+			gr->has_bind_display = false;
+	}
+
+	if (weston_check_egl_extension(extensions,
+				"EGL_EXT_image_dma_buf_import_modifiers")) {
+		gr->query_dmabuf_formats =
+			(void *) eglGetProcAddress("eglQueryDmaBufFormatsEXT");
+		gr->query_dmabuf_modifiers =
+			(void *) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
+		assert(gr->query_dmabuf_formats);
+		assert(gr->query_dmabuf_modifiers);
+		gr->has_dmabuf_import_modifiers = true;
+	}
+
+	return 0;
+}
+
+static int
+create_default_dmabuf_feedback(struct weston_compositor *ec,
+			       struct g2d_renderer *gr)
+{
+	struct stat dev_stat;
+	struct weston_dmabuf_feedback_tranche *tranche;
+	uint32_t flags = 0;
+
+	if (stat(gr->drm_device, &dev_stat) != 0) {
+		weston_log("%s: device disappeared, so we can't recover\n", __func__);
+		abort();
+	}
+
+	ec->default_dmabuf_feedback =
+		weston_dmabuf_feedback_create(dev_stat.st_rdev);
+	if (!ec->default_dmabuf_feedback)
+		return -1;
+
+	tranche =
+		weston_dmabuf_feedback_tranche_create(ec->default_dmabuf_feedback,
+						      ec->dmabuf_feedback_format_table,
+						      dev_stat.st_rdev, flags,
+						      RENDERER_PREF);
+	if (!tranche) {
+		weston_dmabuf_feedback_destroy(ec->default_dmabuf_feedback);
+		ec->default_dmabuf_feedback = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+g2d_renderer_create(struct weston_compositor *ec)
+{
+	struct g2d_renderer *gr;
+	int g2d_hardware_available = 0;
+
+	gr = calloc(1, sizeof *gr);
+	if (gr == NULL)
+		return -1;
+
+	weston_drm_format_array_init(&gr->supported_formats);
+
+	gr->base.read_pixels = g2d_renderer_read_pixels;
+	gr->base.repaint_output = g2d_renderer_repaint_output;
+	gr->base.flush_damage = g2d_renderer_flush_damage;
+	gr->base.resize_output = g2d_renderer_resize_output;
+	gr->base.attach = g2d_renderer_attach;
+	gr->base.destroy = g2d_renderer_destroy;
+	gr->base.import_dmabuf = g2d_renderer_import_dmabuf;
+	gr->base.get_supported_formats = g2d_renderer_get_supported_formats;
+	gr->base.fill_buffer_info = g2d_renderer_fill_buffer_info;
+	gr->base.type = WESTON_RENDERER_G2D;
+	ec->renderer = &gr->base;
+#ifdef ENABLE_EGL
+	gr->bind_display =
+		(void *) eglGetProcAddress("eglBindWaylandDisplayWL");
+	gr->unbind_display =
+		(void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
+	gr->query_buffer =
+		(void *) eglGetProcAddress("eglQueryWaylandBufferWL");
+	gr->update_buffer =
+		(void *) eglGetProcAddress("eglUpdateWaylandBufferWL");
+	gr->query_display_attrib =
+		(void *) eglGetProcAddress("eglQueryDisplayAttribEXT");
+	gr->query_device_string =
+		(void *) eglGetProcAddress("eglQueryDeviceStringEXT");
+	if (!get_platform_display)
+	{
+		get_platform_display = (void *) eglGetProcAddress(
+				"eglGetPlatformDisplayEXT");
+	}
+
+	ec->capabilities |= WESTON_CAP_EXPLICIT_SYNC;
+#endif
+	if(g2d_open(&gr->handle))
+	{
+		weston_log("g2d_open fail.\n");
+		return -1;
+	}
+
+	ec->capabilities |= WESTON_CAP_ROTATION_ANY;
+	ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
+	ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
+	ec->read_format = pixel_format_get_info_by_pixman(PIXMAN_a8r8g8b8);
+
+	g2d_query_hardware(gr->handle, G2D_HARDWARE_PXP, &g2d_hardware_available);
+
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_BGR565);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV420);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YVU420);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV12);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV16);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV21);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUYV);
+	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_UYVY);
+	if(g2d_hardware_available != 1)
+	{
+		wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_XBGR8888);
+		wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_BGRX8888);
+		wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGBX8888);
+		wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_ABGR8888);
+		wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_BGRA8888);
+		wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGBA8888);
+	}
+
+	wl_signal_init(&gr->destroy_signal);
+
+	create_g2d_file();
+
+	return 0;
+}
+
+static int
+g2d_drm_display_create(struct weston_compositor *ec, void *native_window)
+{
+	struct g2d_renderer *gr;
+#ifdef ENABLE_EGL
+	int ret;
+#endif
+
+	if(g2d_renderer_create(ec) < 0)
+	{
+		weston_log("g2d_renderer_create faile.\n");
+		return -1;
+	}
+#ifdef ENABLE_EGL
+	gr = get_renderer(ec);
+	gr->wl_display = ec->wl_display;
+
+	if (g2d_renderer_setup_egl_client_extensions(gr) < 0)
+		goto fail;
+
+	if (g2d_renderer_setup_egl_display(gr, native_window) < 0)
+		goto fail;
+
+	if (g2d_renderer_setup_egl_extensions(gr) < 0)
+		goto fail;
+
+	ret = populate_supported_formats(ec, &gr->supported_formats);
+	if (ret < 0)
+		goto fail_terminate;
+
+	if (gr->drm_device) {
+		/* We support dma-buf feedback only when the renderer
+		 * exposes a DRM-device */
+		ec->dmabuf_feedback_format_table =
+			weston_dmabuf_feedback_format_table_create(&gr->supported_formats);
+		if (!ec->dmabuf_feedback_format_table)
+			goto fail_terminate;
+		ret = create_default_dmabuf_feedback(ec, gr);
+		if (ret < 0)
+			goto fail_feedback;
+	}
+#endif
+	gr->use_drm = 1;
+
+	return 0;
+
+fail_terminate:
+	weston_drm_format_array_fini(&gr->supported_formats);
+	eglTerminate(gr->egl_display);
+fail_feedback:
+	weston_dmabuf_feedback_format_table_destroy(ec->dmabuf_feedback_format_table);
+	ec->dmabuf_feedback_format_table = NULL;
+fail:
+	free(gr);
+	ec->renderer = NULL;
+
+	return -1;
+}
+
+static void
+g2d_renderer_output_set_buffer(struct weston_output *output, struct g2d_surfaceEx *buffer)
+{
+	struct g2d_output_state *go = get_output_state(output);
+	go->drm_hw_buffer = buffer;
+}
+
+static int
+g2d_renderer_get_surface_fence_fd(struct g2d_surfaceEx *buffer)
+{
+	return buffer->reserved[0];
+}
+
+static int
+g2d_drm_renderer_output_create(struct weston_output *output,
+				 const struct g2d_renderer_output_options *options)
+{
+	struct g2d_output_state *go;
+	int i = 0;
+
+	go = zalloc(sizeof *go);
+	if (go == NULL)
+		return -1;
+	output->renderer_state = go;
+
+	for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
+		pixman_region32_init(&go->buffer_damage[i]);
+
+	if (!g2d_renderer_resize_output(output, &options->fb_size, &options->area)) {
+		weston_log("Output %s failed to create 16F shadow.\n",
+			   output->name);
+		output->renderer_state = NULL;
+		free(go);
+		return -1;
+	}
+
+	return 0;
+ }
+
+static int
+drm_create_g2d_image(struct g2d_surfaceEx* g2dSurface,
+				enum g2d_format g2dFormat,
+				void *vaddr,
+				int w, int h, int stride,
+				int size,
+				int dmafd)
+{
+	struct g2d_buf * buffer = NULL;
+
+	buffer = g2d_buf_from_fd(dmafd);
+	if (!buffer)
+		return -1;
+
+	buffer->buf_vaddr = vaddr;
+	buffer->buf_size  = size;
+	g2dSurface->base.planes[0] = buffer->buf_paddr;
+	g2dSurface->base.left = 0;
+	g2dSurface->base.top  = 0;
+	g2dSurface->base.right	= w;
+	g2dSurface->base.bottom = h;
+	g2dSurface->base.stride = w;
+	g2dSurface->base.width	= w;
+	g2dSurface->base.height = h;
+	g2dSurface->base.format = g2dFormat;
+	g2dSurface->base.rot	= G2D_ROTATION_0;
+	g2dSurface->base.clrcolor = 0xFF400000;
+	g2dSurface->tiling = G2D_LINEAR;
+	g2dSurface->reserved[0] = -1;
+
+	return 0;
+}
+
+ WL_EXPORT struct g2d_renderer_interface g2d_renderer_interface = {
+	.create = g2d_renderer_create,
+	.drm_display_create  = g2d_drm_display_create,
+	.drm_output_create   = g2d_drm_renderer_output_create,
+	.create_g2d_image    = drm_create_g2d_image,
+	.output_set_buffer   = g2d_renderer_output_set_buffer,
+	.output_destroy      = g2d_renderer_output_destroy,
+	.get_surface_fence_fd = g2d_renderer_get_surface_fence_fd,
+};
diff --git a/libweston/renderer-g2d/g2d-renderer.h b/libweston/renderer-g2d/g2d-renderer.h
new file mode 100644
index 00000000..214e4214
--- /dev/null
+++ b/libweston/renderer-g2d/g2d-renderer.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015 Freescale Semiconductor, Inc.
+ * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __g2d_renderer_h_
+#define __g2d_renderer_h_
+
+#include <libweston/libweston.h>
+#include "backend.h"
+#include "libweston-internal.h"
+
+#include <g2dExt.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+#include <assert.h>
+
+#ifdef ENABLE_EGL
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
+struct g2d_renderer_output_options {
+	struct weston_size fb_size;
+	struct weston_geometry area;
+	const struct pixel_format_info *formats;
+	unsigned formats_count;
+};
+
+struct g2d_renderer_interface {
+	int (*create)(struct weston_compositor *ec);
+
+	int (*drm_display_create)(struct weston_compositor *ec, void *native_window);
+
+	int (*drm_output_create)(struct weston_output *output,
+				const struct g2d_renderer_output_options *options);
+
+	int (*create_g2d_image)(struct g2d_surfaceEx* g2dSurface,
+				enum g2d_format g2dFormat,
+				void *vaddr,
+				int w, int h, int stride,
+				int size,
+				int dmafd);
+
+	void (*output_set_buffer)(struct weston_output *output,
+				struct g2d_surfaceEx *buffer);
+
+	void (*output_destroy)(struct weston_output *output);
+
+	int (*get_surface_fence_fd)(struct g2d_surfaceEx *buffer);
+};
+
+#endif
diff --git a/libweston/renderer-g2d/meson.build b/libweston/renderer-g2d/meson.build
new file mode 100644
index 00000000..52f80bf7
--- /dev/null
+++ b/libweston/renderer-g2d/meson.build
@@ -0,0 +1,42 @@
+if not get_option('renderer-g2d')
+	subdir_done()
+endif
+
+config_h.set('ENABLE_EGL', '1')
+config_h.set('ENABLE_IMXG2D', '1')
+
+srcs_renderer_g2d = [
+	'g2d-renderer.c',
+	linux_dmabuf_unstable_v1_protocol_c,
+	linux_dmabuf_unstable_v1_server_protocol_h,
+]
+
+dep_g2d = cc.find_library('g2d')
+
+deps_renderer_g2d = [
+	dep_libm,
+	dep_pixman,
+	dep_libweston_private,
+	dep_libdrm_headers,
+	dep_vertex_clipping,
+	dep_g2d,
+]
+
+foreach name : [ 'egl' ]
+	d = dependency(name, required: false)
+	if not d.found()
+		error('g2d-renderer requires @0@ which was not found. Or, you can use \'-Drenderer-g2d=false\'.'.format(name))
+	endif
+	deps_renderer_g2d += d
+endforeach
+
+plugin_g2d = shared_library(
+	'g2d-renderer',
+	srcs_renderer_g2d,
+	include_directories: common_inc,
+	dependencies: deps_renderer_g2d,
+	name_prefix: '',
+	install: true,
+	install_dir: dir_module_libweston
+)
+env_modmap += 'g2d-renderer.so=@0@;'.format(plugin_g2d.full_path())
diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c
index 4a6da14f..2ad8fa7c 100644
--- a/libweston/renderer-gl/gl-renderer.c
+++ b/libweston/renderer-gl/gl-renderer.c
@@ -1163,6 +1163,58 @@ gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf,
 	return true;
 }
 
+static void
+draw_through_hole(struct weston_paint_node *pnode,
+		pixman_region32_t *output_region /* in global coordinates */)
+{
+	struct gl_renderer *gr = get_renderer(pnode->surface->compositor);
+	struct gl_output_state *go = get_output_state(pnode->output);
+
+	/* repaint bounding region in global coordinates: */
+	pixman_region32_t repaint;
+	/* through hole region in surface coordinates: */
+	pixman_region32_t surface_hole;
+
+	/* set shader conf for through hole */
+	struct gl_shader_config sconf = {
+		.req = {
+			/* set to SOLID, shader will draw a solid color region */
+			.variant = SHADER_VARIANT_SOLID,
+			.input_is_premult = true,
+		},
+		.projection = go->output_matrix,
+		/* through hole need to be a colorless opaque region */
+		.view_alpha = 1.0,
+		.unicolor = { 0.0, 0.0, 0.0, 0.0 },
+		/* Not necessary, beacuse for solid surface,
+		 * shader will use unicolor not textture */
+		.input_tex = {0, 0, 0}
+	};
+
+	/* Disable color blend. This will allow through
+	 * hole cover the color below, so that the video on underlay
+	 * plane will be displayed */
+	glDisable(GL_BLEND);
+
+	pixman_region32_init(&repaint);
+	pixman_region32_intersect(&repaint,
+				  &pnode->view->transform.boundingbox, output_region);
+	pixman_region32_subtract(&repaint, &repaint, &pnode->view->clip);
+
+	if (!pixman_region32_not_empty(&repaint)) {
+		pixman_region32_fini(&repaint);
+		return;
+	}
+
+	pixman_region32_init_rect(&surface_hole, 0, 0,
+				  pnode->surface->width, pnode->surface->height);
+
+	repaint_region(gr, pnode, &repaint, &surface_hole, &sconf);
+
+	pixman_region32_fini(&surface_hole);
+	pixman_region32_fini(&repaint);
+}
+
 static void
 draw_paint_node(struct weston_paint_node *pnode,
 		pixman_region32_t *damage /* in global coordinates */)
@@ -1272,6 +1324,8 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
 				 z_order_link) {
 		if (pnode->view->plane == &compositor->primary_plane)
 			draw_paint_node(pnode, damage);
+		else if (pnode->need_through_hole)
+			draw_through_hole(pnode, &output->region);
 	}
 
 	glDisableVertexAttribArray(1);
@@ -2950,6 +3004,21 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
 		return true;
 	}
 
+	/**
+	 * if backend can handle dmabuf directly, then we only need set
+	 * size to buffer.
+	 * */
+	if (surface->compositor->backend->import_dmabuf) {
+		struct weston_compositor *compositor = surface->compositor;
+		struct weston_backend *backend = surface->compositor->backend;
+		if (backend->import_dmabuf(compositor, dmabuf)){
+			attach_direct_display_censor_placeholder(surface, buffer);
+			buffer->width = dmabuf->attributes.width;
+			buffer->height = dmabuf->attributes.height;
+			return true;
+		}
+	}
+
 	/* Thanks to linux-dmabuf being totally independent of libweston,
 	 * the first time a dmabuf is attached, the gl_buffer_state will
 	 * only be set as userdata on the dmabuf, not on the weston_buffer.
@@ -3919,7 +3988,6 @@ gl_renderer_display_create(struct weston_compositor *ec,
 
 	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
 	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV420);
-	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV444);
 	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV12);
 	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUYV);
 	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_XYUV8888);
diff --git a/libweston/touch-calibration.c b/libweston/touch-calibration.c
index bbef89fc..224279e3 100644
--- a/libweston/touch-calibration.c
+++ b/libweston/touch-calibration.c
@@ -209,6 +209,8 @@ map_calibrator(struct weston_touch_calibrator *calibrator)
 	weston_surface_map(calibrator->surface);
 
 	weston_output_schedule_repaint(calibrator->output);
+	weston_view_geometry_dirty(calibrator->view);
+	weston_view_update_transform(calibrator->view);
 
 	device->ops->get_calibration(device, &device->saved_calibration);
 	device->ops->set_calibration(device, &identity);
diff --git a/meson.build b/meson.build
index 1e68812f..89d84236 100644
--- a/meson.build
+++ b/meson.build
@@ -113,6 +113,7 @@ config_h.set_quoted('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/wayland
 
 config_h.set_quoted('BINDIR', dir_bin)
 config_h.set_quoted('DATADIR', dir_data)
+config_h.set_quoted('LIBDIR', dir_lib)
 config_h.set_quoted('LIBEXECDIR', dir_libexec)
 config_h.set_quoted('MODULEDIR', dir_module_weston)
 config_h.set_quoted('LIBWESTON_MODULEDIR', dir_module_libweston)
@@ -149,6 +150,11 @@ dep_threads = dependency('threads')
 
 dep_lcms2 = dependency('lcms2', version: '>= 2.9', required: false)
 
+dep_libdrm_version = dep_libdrm.version()
+if dep_libdrm_version.version_compare('>=2.4.107')
+  config_h.set('USE_DRM_FORMAT_NV15', '1')
+endif
+
 prog_python = import('python').find_installation('python3')
 files_xxd_py = files('tools/xxd.py')
 cmd_xxd = [ prog_python, files_xxd_py, '@INPUT@', '@OUTPUT@' ]
diff --git a/meson_options.txt b/meson_options.txt
index e132be9e..643c6d61 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -71,6 +71,13 @@ option(
 	description: 'Weston renderer: EGL / OpenGL ES 2.x'
 )
 
+option(
+	'renderer-g2d',
+	type: 'boolean',
+	value: true,
+	description: 'Weston renderer: G2D, i.MX G2D support'
+)
+
 option(
 	'xwayland',
 	type: 'boolean',
diff --git a/protocol/meson.build b/protocol/meson.build
index b055816b..84eb8b9b 100644
--- a/protocol/meson.build
+++ b/protocol/meson.build
@@ -1,4 +1,4 @@
-dep_scanner = dependency('wayland-scanner', native: true)
+dep_scanner = dependency('wayland-scanner', native: false)
 prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner'))
 
 dep_wp = dependency('wayland-protocols', version: '>= 1.31',
@@ -44,6 +44,7 @@ generated_protocols = [
 	[ 'xdg-shell', 'unstable', 'v6' ],
 	[ 'xdg-shell', 'stable' ],
 	[ 'xwayland-shell', 'staging', 'v1' ],
+	[ 'hdr10-metadata', 'unstable', 'v1' ],
 ]
 
 foreach proto: generated_protocols
diff --git a/shared/config-parser.c b/shared/config-parser.c
index 749158df..755348c0 100644
--- a/shared/config-parser.c
+++ b/shared/config-parser.c
@@ -363,6 +363,19 @@ weston_config_get_name_from_env(void)
 	return "weston.ini";
 }
 
+WL_EXPORT
+void
+weston_config_set_env(struct weston_config_section *section)
+{
+	struct weston_config_entry *e;
+
+	if (section == NULL)
+		return;
+	wl_list_for_each(e, &section->entry_list, link) {
+		setenv(e->key, e->value, 1);
+	}
+}
+
 static struct weston_config_section *
 config_add_section(struct weston_config *config, const char *name)
 {
diff --git a/weston.ini.in b/weston.ini.in
index d3180cce..54cd5072 100644
--- a/weston.ini.in
+++ b/weston.ini.in
@@ -1,88 +1,37 @@
 [core]
-#modules=cms-colord.so
-#xwayland=true
-#shell=desktop
-#gbm-format=xrgb2101010
-#require-input=true
+#gbm-format=argb8888
+idle-time=0
+#use-g2d=true
+xwayland=true
+#repaint-window=16
+#enable-overlay-view=1
+modules=screen-share.so
 
-[shell]
-background-image=/usr/share/backgrounds/gnome/Aqua.jpg
-background-color=0xff002244
-background-type=tile
-clock-format=minutes
-panel-color=0x90ff0000
-locking=true
-animation=zoom
-startup-animation=fade
-#binding-modifier=ctrl
-#num-workspaces=6
-#cursor-theme=whiteglass
-#cursor-size=24
+#[shell]
+#size=1920x1080
 
-#animation=fade
+[libinput]
+touchscreen_calibrator=true
 
-[launcher]
-icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
-path=/usr/bin/gnome-terminal
-displayname=Gnome Terminal
-
-[launcher]
-icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
-path=@bindir@/weston-terminal
-displayname=Weston Terminal
-
-[launcher]
-icon=/usr/share/icons/hicolor/24x24/apps/google-chrome.png
-path=/usr/bin/google-chrome
-displayname=Google Chome
-
-[launcher]
-icon=/usr/share/icons/gnome/24x24/apps/arts.png
-path=@bindir@/weston-flower
-displayname=Weston Flower
-
-[input-method]
-path=@libexecdir@/weston-keyboard
+#[environment-variables]
+#GBM_MULTI_BUFFER=3
 
 #[output]
-#name=LVDS1
-#mode=1680x1050
-#transform=90
-#icc_profile=/usr/share/color/icc/colord/Bluish.icc
+#name=HDMI-A-1
+#mode=1920x1080@60
+#transform=rotate-90
 
 #[output]
-#name=VGA1
-#mode=173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
-#transform=flipped
-
-#[output]
-#name=X1
-#mode=1024x768@60
-#transform=flipped-90
-
-#[libinput]
-#enable-tap=true
-#tap-and-drag=true
-#tap-and-drag-lock=true
-#disable-while-typing=false
-#middle-button-emulation=true
-#left-handed=true
-#rotation=90
-#accel-profile=flat
-#accel-speed=.9
-#natural-scroll=true
-#scroll-method=edge
-# For button-triggered scrolling:
-#scroll-method=button
-#scroll-button=BTN_RIGHT
-
-#[touchpad]
-#constant_accel_factor = 50
-#min_accel_factor = 0.16
-#max_accel_factor = 1.0
+#name=HDMI-A-2
+#mode=off
+#	WIDTHxHEIGHT    Resolution size width and height in pixels
+#	off             Disables the output
+#	preferred       Uses the preferred mode
+#	current         Uses the current crt controller mode
+#transform=rotate-90
 
 [screen-share]
-command=@bindir@/weston --backend=rdp --shell=fullscreen --no-clients-resize
+command=@bindir@/weston --backend=rdp --shell=fullscreen --no-clients-resize --rdp-tls-cert=/etc/freerdp/keys/server.crt --rdp-tls-key=/etc/freerdp/keys/server.key
 #start-on-startup=false
 
 #[xwayland]
diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c
index 36441fa6..e03ee701 100644
--- a/xwayland/window-manager.c
+++ b/xwayland/window-manager.c
@@ -951,6 +951,7 @@ weston_wm_create_surface(struct wl_listener *listener, void *data)
 			xserver_map_shell_surface(window, surface);
 			window->surface_id = 0;
 			wl_list_remove(&window->link);
+			wl_list_init(&window->link);
 			break;
 		}
 }
@@ -1672,8 +1673,7 @@ weston_wm_window_destroy(struct weston_wm_window *window)
 	if (window->frame)
 		frame_destroy(window->frame);
 
-	if (window->surface_id)
-		wl_list_remove(&window->link);
+	wl_list_remove(&window->link);
 
 	if (window->surface)
 		wl_list_remove(&window->surface_destroy_listener.link);
