[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/meta/meta-mediatek/recipes-graphics/disppq/disppq.bb b/meta/meta-mediatek/recipes-graphics/disppq/disppq.bb
new file mode 100644
index 0000000..87c4b6e
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/disppq/disppq.bb
@@ -0,0 +1,29 @@
+DESCRIPTION = "MediaTek PQ daemon"
+LICENSE = "MediaTekProprietary"
+
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/disppq"
+
+DEPENDS = "drm"
+
+inherit pkgconfig
+
+do_configure() {
+ :
+}
+
+do_compile() {
+ oe_runmake \
+ TARGET_PLATFORM="${TARGET_PLATFORM}" \
+ CFLAGS+="${CFLAGS} -I${STAGING_INCDIR}/drm"
+}
+
+do_install() {
+ oe_runmake \
+ PREFIX="${prefix}" PACKAGE_ARCH="${PACKAGE_ARCH}" TARGET_PLATFORM="${TARGET_PLATFORM}" DESTDIR="${D}" LIBDIR="${libdir}" INCDIR="${includedir}" install
+}
+
+FILES_${PN}-dev = ""
+FILES_${PN} += "${includedir} ${libdir} ${bindir} ${sysconfdir}/pq"
+
+
diff --git a/meta/meta-mediatek/recipes-graphics/libaal/libaal.bb b/meta/meta-mediatek/recipes-graphics/libaal/libaal.bb
new file mode 100644
index 0000000..4dcf80e
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/libaal/libaal.bb
@@ -0,0 +1,28 @@
+DESCRIPTION = "MediaTek AAL daemon"
+LICENSE = "MediaTekProprietary"
+
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../prebuilt/graphics/libaal"
+
+inherit pkgconfig
+
+do_configure() {
+ :
+}
+
+do_compile() {
+ oe_runmake \
+ TARGET_PLATFORM="${TARGET_PLATFORM}" \
+ CFLAGS+="${CFLAGS}"
+}
+
+do_install() {
+ kernel_version=v`echo "${PREFERRED_VERSION_linux-mtk-extension}" | cut -d "%" -f 1`
+ oe_runmake \
+ PREFIX="${prefix}" PACKAGE_ARCH="${PACKAGE_ARCH}" TARGET_PLATFORM="${TARGET_PLATFORM}" kernel_version="${kernel_version}" DESTDIR="${D}" LIBDIR="${libdir}" INCDIR="${includedir}" install
+}
+
+INSANE_SKIP_${PN} += "already-stripped"
+FILES_${PN}-dev = ""
+FILES_${PN} += "${includedir} ${libdir} ${bindir}"
+
diff --git a/meta/meta-mediatek/recipes-graphics/libdrm/files/0001-Sync-drm-headfile-with-the-kernel.patch b/meta/meta-mediatek/recipes-graphics/libdrm/files/0001-Sync-drm-headfile-with-the-kernel.patch
new file mode 100644
index 0000000..b5f22e9
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/libdrm/files/0001-Sync-drm-headfile-with-the-kernel.patch
@@ -0,0 +1,131 @@
+From e379c6a137bba5c40d9a126b71a667b4d7f5697a Mon Sep 17 00:00:00 2001
+From: Daniel Stone <daniels@collabora.com>
+Date: Tue, 4 Apr 2017 21:38:56 +0100
+Subject: [PATCH] Headers: Sync drm{,_mode}.h with the kernel
+
+Generated using make headers_install, based on drm-misc-next commit
+5db06a8a98f515f67446a69c57577c4c363ec65d.
+
+This clarifies the comments around modifiers such that they are
+per-framebuffer rather than per-plane, adds the beginnings of aspect
+ratio mode flags, link status properties, and updates the 'reserved'
+field from vblank events to include the CRTC ID.
+
+v2: Split into separate patch, pull in full kernel changes.
+v3: Undo revert of connector-type enums, since it is not actually
+ harmful.
+
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
+---
+ include/drm/drm.h | 3 ++-
+ include/drm/drm_mode.h | 45 +++++++++++++++++++++++++++++++--------------
+ 2 files changed, 33 insertions(+), 15 deletions(-)
+
+diff --git a/include/drm/drm.h b/include/drm/drm.h
+index f6fd5c2..1e7a4bc 100644
+--- a/include/drm/drm.h
++++ b/include/drm/drm.h
+@@ -641,6 +641,7 @@ struct drm_gem_open {
+ #define DRM_CAP_CURSOR_HEIGHT 0x9
+ #define DRM_CAP_ADDFB2_MODIFIERS 0x10
+ #define DRM_CAP_PAGE_FLIP_TARGET 0x11
++#define DRM_CAP_CRTC_IN_VBLANK_EVENT 0x12
+
+ /** DRM_IOCTL_GET_CAP ioctl argument type */
+ struct drm_get_cap {
+@@ -845,7 +846,7 @@ struct drm_event_vblank {
+ __u32 tv_sec;
+ __u32 tv_usec;
+ __u32 sequence;
+- __u32 reserved;
++ __u32 crtc_id; /* 0 on older kernels that do not support this */
+ };
+
+ /* typedef area */
+diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
+index df0e350..70571af 100644
+--- a/include/drm/drm_mode.h
++++ b/include/drm/drm_mode.h
+@@ -47,7 +47,15 @@ extern "C" {
+ #define DRM_MODE_TYPE_DRIVER (1<<6)
+
+ /* Video mode flags */
+-/* bit compatible with the xorg definitions. */
++/* bit compatible with the xrandr RR_ definitions (bits 0-13)
++ *
++ * ABI warning: Existing userspace really expects
++ * the mode flags to match the xrandr definitions. Any
++ * changes that don't match the xrandr definitions will
++ * likely need a new client cap or some other mechanism
++ * to avoid breaking existing userspace. This includes
++ * allocating new flags in the previously unused bits!
++ */
+ #define DRM_MODE_FLAG_PHSYNC (1<<0)
+ #define DRM_MODE_FLAG_NHSYNC (1<<1)
+ #define DRM_MODE_FLAG_PVSYNC (1<<2)
+@@ -107,6 +115,10 @@ extern "C" {
+ #define DRM_MODE_DIRTY_ON 1
+ #define DRM_MODE_DIRTY_ANNOTATE 2
+
++/* Link Status options */
++#define DRM_MODE_LINK_STATUS_GOOD 0
++#define DRM_MODE_LINK_STATUS_BAD 1
++
+ struct drm_mode_modeinfo {
+ __u32 clock;
+ __u16 hdisplay;
+@@ -220,14 +232,16 @@ struct drm_mode_get_encoder {
+
+ /* This is for connectors with multiple signal types. */
+ /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
+-#define DRM_MODE_SUBCONNECTOR_Automatic 0
+-#define DRM_MODE_SUBCONNECTOR_Unknown 0
+-#define DRM_MODE_SUBCONNECTOR_DVID 3
+-#define DRM_MODE_SUBCONNECTOR_DVIA 4
+-#define DRM_MODE_SUBCONNECTOR_Composite 5
+-#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
+-#define DRM_MODE_SUBCONNECTOR_Component 8
+-#define DRM_MODE_SUBCONNECTOR_SCART 9
++enum drm_mode_subconnector {
++ DRM_MODE_SUBCONNECTOR_Automatic = 0,
++ DRM_MODE_SUBCONNECTOR_Unknown = 0,
++ DRM_MODE_SUBCONNECTOR_DVID = 3,
++ DRM_MODE_SUBCONNECTOR_DVIA = 4,
++ DRM_MODE_SUBCONNECTOR_Composite = 5,
++ DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
++ DRM_MODE_SUBCONNECTOR_Component = 8,
++ DRM_MODE_SUBCONNECTOR_SCART = 9,
++};
+
+ #define DRM_MODE_CONNECTOR_Unknown 0
+ #define DRM_MODE_CONNECTOR_VGA 1
+@@ -392,17 +406,20 @@ struct drm_mode_fb_cmd2 {
+ * offsets[1]. Note that offsets[0] will generally
+ * be 0 (but this is not required).
+ *
+- * To accommodate tiled, compressed, etc formats, a per-plane
++ * To accommodate tiled, compressed, etc formats, a
+ * modifier can be specified. The default value of zero
+ * indicates "native" format as specified by the fourcc.
+- * Vendor specific modifier token. This allows, for example,
+- * different tiling/swizzling pattern on different planes.
+- * See discussion above of DRM_FORMAT_MOD_xxx.
++ * Vendor specific modifier token. Note that even though
++ * it looks like we have a modifier per-plane, we in fact
++ * do not. The modifier for each plane must be identical.
++ * Thus all combinations of different data layouts for
++ * multi plane formats must be enumerated as separate
++ * modifiers.
+ */
+ __u32 handles[4];
+ __u32 pitches[4]; /* pitch for each plane */
+ __u32 offsets[4]; /* offset of each plane */
+- __u64 modifier[4]; /* ie, tiling, compressed (per plane) */
++ __u64 modifier[4]; /* ie, tiling, compress */
+ };
+
+ #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01
+--
+libgit2 0.26.0
+
diff --git a/meta/meta-mediatek/recipes-graphics/libdrm/files/0002-Add-CRTC-ID-to-vblank-event.patch b/meta/meta-mediatek/recipes-graphics/libdrm/files/0002-Add-CRTC-ID-to-vblank-event.patch
new file mode 100644
index 0000000..1519dc2
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/libdrm/files/0002-Add-CRTC-ID-to-vblank-event.patch
@@ -0,0 +1,100 @@
+From 890d43a6a8d091211b82dd432af5e0a38472ffa6 Mon Sep 17 00:00:00 2001
+From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
+Date: Mon, 17 Aug 2015 16:21:24 +0300
+Subject: [PATCH] Add CRTC ID to vblank event
+
+When using the atomic API, one request can span multiple CRTCs, however
+one event is generated per CRTC. As we cannot disambiguate the CRTC with
+user data (since we only have one piece of user data to pass in), newer
+kernels can include the CRTC ID in the page flip event.
+
+Add a new vfunc to dispatch vblank events carrying a CRTC ID to clients
+who negotiate a higher interface version.
+
+[daniels: Rebased, include new cap, call page_flip_handler if it is set
+ but page_flip_handler2 isn't even on newer contexts, write a
+ commit message.]
+
+v2: Split into separate commit.
+
+Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
+Signed-off-by: Daniel Stone <daniels@collabora.com>
+Reviewed-by: Maarten Lankhorst <maarten.lankhorst@intel.com>
+---
+ xf86drm.h | 9 ++++++++-
+ xf86drmMode.c | 24 ++++++++++++++++--------
+ 2 files changed, 24 insertions(+), 9 deletions(-)
+
+diff --git a/xf86drm.h b/xf86drm.h
+index 0d92701..d75ca8c 100644
+--- a/xf86drm.h
++++ b/xf86drm.h
+@@ -728,7 +728,7 @@ extern void drmMsg(const char *format, ...) DRM_PRINTFLIKE(1, 2);
+ extern int drmSetMaster(int fd);
+ extern int drmDropMaster(int fd);
+
+-#define DRM_EVENT_CONTEXT_VERSION 2
++#define DRM_EVENT_CONTEXT_VERSION 3
+
+ typedef struct _drmEventContext {
+
+@@ -748,6 +748,13 @@ typedef struct _drmEventContext {
+ unsigned int tv_usec,
+ void *user_data);
+
++ void (*page_flip_handler2)(int fd,
++ unsigned int sequence,
++ unsigned int tv_sec,
++ unsigned int tv_usec,
++ unsigned int crtc_id,
++ void *user_data);
++
+ } drmEventContext, *drmEventContextPtr;
+
+ extern int drmHandleEvent(int fd, drmEventContextPtr evctx);
+diff --git a/xf86drmMode.c b/xf86drmMode.c
+index 0266bc1..d3bc20e 100644
+--- a/xf86drmMode.c
++++ b/xf86drmMode.c
+@@ -889,6 +889,7 @@ int drmHandleEvent(int fd, drmEventContextPtr evctx)
+ int len, i;
+ struct drm_event *e;
+ struct drm_event_vblank *vblank;
++ void *user_data;
+
+ /* The DRM read semantics guarantees that we always get only
+ * complete events. */
+@@ -915,15 +916,22 @@ int drmHandleEvent(int fd, drmEventContextPtr evctx)
+ U642VOID (vblank->user_data));
+ break;
+ case DRM_EVENT_FLIP_COMPLETE:
+- if (evctx->version < 2 ||
+- evctx->page_flip_handler == NULL)
+- break;
+ vblank = (struct drm_event_vblank *) e;
+- evctx->page_flip_handler(fd,
+- vblank->sequence,
+- vblank->tv_sec,
+- vblank->tv_usec,
+- U642VOID (vblank->user_data));
++ user_data = U642VOID (vblank->user_data);
++
++ if (evctx->version >= 3 && evctx->page_flip_handler2)
++ evctx->page_flip_handler2(fd,
++ vblank->sequence,
++ vblank->tv_sec,
++ vblank->tv_usec,
++ vblank->crtc_id,
++ user_data);
++ else if (evctx->version >= 2 && evctx->page_flip_handler)
++ evctx->page_flip_handler(fd,
++ vblank->sequence,
++ vblank->tv_sec,
++ vblank->tv_usec,
++ user_data);
+ break;
+ default:
+ break;
+--
+libgit2 0.26.0
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r15p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r15p0.bb
new file mode 100644
index 0000000..1cef0ad
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r15p0.bb
@@ -0,0 +1,131 @@
+DESCRIPTION = "Mali-Bifrost GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/bifrost/NOTICE;md5=ccf6b0dfe7f9ae14e0d41187f7b05ef9"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/bifrost/r15p0"
+
+DEPENDS = "libdrm wayland python-scons-native"
+PROVIDES = "virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} CROSS=${TARGET_PREFIX}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4.0
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${libdir}/libOpenCL.so* \
+ ${bindir}/mali_base_jd_test \
+ ${bindir}/mali_gles_integration_suite \
+ ${bindir}/mali_egl_integration_tests \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_example_cpp \
+ ${bindir}/mali_cl_simple_example \
+ ${bindir}/mali_cl_svm_opencl_example \
+ ${bindir}/mali_cl_peak_flops_example \
+ ${bindir}/mali_cl_import_memory_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "ldflags"
+INSANE_SKIP_${PN}-dev += "ldflags"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r16p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r16p0.bb
new file mode 100644
index 0000000..8bb9757
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r16p0.bb
@@ -0,0 +1,131 @@
+DESCRIPTION = "Mali-Bifrost GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/bifrost/NOTICE;md5=ccf6b0dfe7f9ae14e0d41187f7b05ef9"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/bifrost/r16p0"
+
+DEPENDS = "libdrm wayland python-scons-native"
+PROVIDES = "virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} CROSS=${TARGET_PREFIX}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4.0
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${libdir}/libOpenCL.so* \
+ ${bindir}/mali_base_jd_test \
+ ${bindir}/mali_gles_integration_suite \
+ ${bindir}/mali_egl_integration_tests \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_example_cpp \
+ ${bindir}/mali_cl_simple_example \
+ ${bindir}/mali_cl_svm_opencl_example \
+ ${bindir}/mali_cl_peak_flops_example \
+ ${bindir}/mali_cl_import_memory_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "ldflags"
+INSANE_SKIP_${PN}-dev += "ldflags"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r19p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r19p0.bb
new file mode 100644
index 0000000..91475eb
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r19p0.bb
@@ -0,0 +1,138 @@
+DESCRIPTION = "Mali-Bifrost GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/bifrost/NOTICE;md5=ccf6b0dfe7f9ae14e0d41187f7b05ef9"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/bifrost/r19p0"
+
+DEPENDS = "libdrm wayland python-scons-native"
+PROVIDES = "virtual/libgbm virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} CROSS=${TARGET_PREFIX}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.1
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4.0
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libOpenCL.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${bindir}/mali_base_jd_test \
+ ${bindir}/mali_gles_integration_suite \
+ ${bindir}/mali_egl_integration_tests \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_example_cpp \
+ ${bindir}/mali_cl_simple_example \
+ ${bindir}/mali_cl_svm_opencl_example \
+ ${bindir}/mali_cl_peak_flops_example \
+ ${bindir}/mali_cl_import_memory_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/cl_va_api_media_sharing_intel.h \
+ ${includedir}/CL/cl_ext_intel.h \
+ ${includedir}/CL/cl_version.h \
+ ${includedir}/CL/cl_dx9_media_sharing_intel.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "ldflags"
+INSANE_SKIP_${PN}-dev += "ldflags"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r20p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r20p0.bb
new file mode 100644
index 0000000..a9c56e3
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_bifrost-r20p0.bb
@@ -0,0 +1,138 @@
+DESCRIPTION = "Mali-Bifrost GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/bifrost/NOTICE;md5=ccf6b0dfe7f9ae14e0d41187f7b05ef9"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/bifrost/r20p0"
+
+DEPENDS = "libdrm wayland python-native python-scons-native"
+PROVIDES = "virtual/libgbm virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} CROSS=${TARGET_PREFIX} TOPDIR=${TOPDIR}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.1
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4.0
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libOpenCL.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${bindir}/mali_base_jd_test \
+ ${bindir}/mali_gles_integration_suite \
+ ${bindir}/mali_egl_integration_tests \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_example_cpp \
+ ${bindir}/mali_cl_simple_example \
+ ${bindir}/mali_cl_svm_opencl_example \
+ ${bindir}/mali_cl_peak_flops_example \
+ ${bindir}/mali_cl_import_memory_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/cl_va_api_media_sharing_intel.h \
+ ${includedir}/CL/cl_ext_intel.h \
+ ${includedir}/CL/cl_version.h \
+ ${includedir}/CL/cl_dx9_media_sharing_intel.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "ldflags"
+INSANE_SKIP_${PN}-dev += "ldflags"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r13p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r13p0.bb
new file mode 100644
index 0000000..ee6ce42
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r13p0.bb
@@ -0,0 +1,125 @@
+DESCRIPTION = "Mali-880 GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/midgard/NOTICE;md5=4610adf2da9e96774ed48a3e3e0fb18f"
+#inherit externalsrc
+#EXTERNALSRC = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+#EXTERNALSRC_BUILD = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/midgard/r13p0"
+
+DEPENDS = "libdrm wayland python-scons-native"
+PROVIDES = "virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} DONWLOADS=${TOPDIR}/../downloads CROSSCOMPILER_PREFIX=${TARGET_PREFIX}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${libdir}/libOpenCL.so* \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_opencl_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r20p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r20p0.bb
new file mode 100644
index 0000000..9b4afa1
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r20p0.bb
@@ -0,0 +1,127 @@
+DESCRIPTION = "Mali-880 GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/midgard/NOTICE;md5=4610adf2da9e96774ed48a3e3e0fb18f"
+#inherit externalsrc
+#EXTERNALSRC = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+#EXTERNALSRC_BUILD = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/midgard/r20p0"
+
+DEPENDS = "libdrm wayland python-scons-native"
+PROVIDES = "virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} DONWLOADS=${TOPDIR}/../downloads CROSS=${TARGET_PREFIX}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${libdir}/libOpenCL.so* \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_opencl_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "ldflags"
+INSANE_SKIP_${PN}-dev += "ldflags"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r26p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r26p0.bb
new file mode 100644
index 0000000..95218c8
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r26p0.bb
@@ -0,0 +1,127 @@
+DESCRIPTION = "Mali-880 GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://${TOPDIR}/../prebuilt/graphics/mali/midgard/NOTICE;md5=4610adf2da9e96774ed48a3e3e0fb18f"
+#inherit externalsrc
+#EXTERNALSRC = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+#EXTERNALSRC_BUILD = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/midgard/r26p0"
+
+DEPENDS = "libdrm wayland python-scons-native"
+PROVIDES = "virtual/libgbm virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake LIB_ROOT=${STAGING_LIBDIR} SYSROOT=${STAGING_DIR_TARGET} REC_SYSROOT=${WORKDIR}/recipe-sysroot STAGING_BINDIR=${STAGING_BINDIR_NATIVE} DONWLOADS=${TOPDIR}/../downloads CROSS=${TARGET_PREFIX}
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" LIB=${libdir} install
+}
+
+do_install_append() {
+ ln -nfs libmali.so ${D}${libdir}/libmali.so.0
+
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libmali.so ${D}${libdir}/libEGL.so.1.4
+
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libmali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libmali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libmali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libmali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1
+ ln -nfs libOpenCL.so ${D}${libdir}/libOpenCL.so.1.1.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libmali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* \
+ ${libdir}/libOpenCL.so* \
+ ${bindir}/mali_cl_unit \
+ ${bindir}/mali_cl_simple_example "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/libOpenCL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3.h \
+ ${includedir}/GLES3/gl3platform.h \
+ ${includedir}/GLES3/gl31.h \
+ ${includedir}/GLES3/gl32.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h \
+ ${includedir}/CL/cl.h \
+ ${includedir}/CL/cl.hpp \
+ ${includedir}/CL/cl_d3d10.h \
+ ${includedir}/CL/cl_d3d11.h \
+ ${includedir}/CL/cl_dx9_media_sharing.h \
+ ${includedir}/CL/cl_egl.h \
+ ${includedir}/CL/cl_ext.h \
+ ${includedir}/CL/cl_gl.h \
+ ${includedir}/CL/cl_gl_ext.h \
+ ${includedir}/CL/cl_platform.h \
+ ${includedir}/CL/opencl.h \
+ ${includedir}/CL_2_0/cl.h \
+ ${includedir}/CL_2_0/cl.hpp \
+ ${includedir}/CL_2_0/cl_d3d10.h \
+ ${includedir}/CL_2_0/cl_d3d11.h \
+ ${includedir}/CL_2_0/cl_dx9_media_sharing.h \
+ ${includedir}/CL_2_0/cl_egl.h \
+ ${includedir}/CL_2_0/cl_ext.h \
+ ${includedir}/CL_2_0/cl_gl.h \
+ ${includedir}/CL_2_0/cl_gl_ext.h \
+ ${includedir}/CL_2_0/cl_platform.h \
+ ${includedir}/CL_2_0/opencl.h \
+ ${includedir}/CL_HPP/cl.hpp \
+ ${includedir}/CL_HPP/cl2.hpp"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "ldflags"
+INSANE_SKIP_${PN}-dev += "ldflags"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r6p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r6p0.bb
new file mode 100644
index 0000000..79d655d
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_midgard-r6p0.bb
@@ -0,0 +1,88 @@
+DESCRIPTION = "Mali-450 GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://NOTICE;md5=4610adf2da9e96774ed48a3e3e0fb18f"
+#inherit externalsrc
+#EXTERNALSRC = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+#EXTERNALSRC_BUILD = "${TOPDIR}/../prebuilt/graphics/mali/midgard"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/midgard"
+
+DEPENDS = "libdrm wayland"
+PROVIDES = "virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake -f Makefile.mediatek
+}
+
+do_install() {
+ oe_runmake -f Makefile.mediatek \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" install
+}
+
+do_install_append() {
+ ln -nfs libMali.so ${D}${libdir}/libMali.so.1
+
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so.1.4
+
+ ln -nfs libMali.so ${D}${libdir}/libgbm.so
+ ln -nfs libMali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libMali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libMali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libMali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libMali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libMali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libMali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libMali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libMali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_utgard-r6p0.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_utgard-r6p0.bb
new file mode 100644
index 0000000..570f2ef
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_utgard-r6p0.bb
@@ -0,0 +1,2 @@
+mali_ver="r6p0"
+require mali_utgard.inc
\ No newline at end of file
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_utgard-r6p2.bb b/meta/meta-mediatek/recipes-graphics/mali/mali_utgard-r6p2.bb
new file mode 100644
index 0000000..234388d
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_utgard-r6p2.bb
@@ -0,0 +1,2 @@
+mali_ver="r6p2"
+require mali_utgard.inc
\ No newline at end of file
diff --git a/meta/meta-mediatek/recipes-graphics/mali/mali_utgard.inc b/meta/meta-mediatek/recipes-graphics/mali/mali_utgard.inc
new file mode 100644
index 0000000..4290471
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mali/mali_utgard.inc
@@ -0,0 +1,91 @@
+DESCRIPTION = "Mali-450 GPU"
+LICENSE = "ARM"
+LIC_FILES_CHKSUM = "file://NOTICE;md5=4c46d84528c2908a46ac79d54284016d"
+#inherit externalsrc
+#EXTERNALSRC = "${TOPDIR}/../prebuilt/graphics/mali/utgard"
+#EXTERNALSRC_BUILD = "${TOPDIR}/../prebuilt/graphics/mali/utgard"
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/graphics/mali/utgard"
+
+DEPENDS = "libdrm wayland"
+PROVIDES = "virtual/egl virtual/libgles1 virtual/libgles2 virtual/libgl virtual/mesa"
+RPROVIDES_${PN} = "libgles2"
+
+inherit pkgconfig
+
+do_compile() {
+ oe_runmake mali_ver="${mali_ver}" -f Makefile.mediatek
+}
+
+do_install() {
+ oe_runmake mali_ver="${mali_ver}" -f Makefile.mediatek \
+ PREFIX="${prefix}" DESTDIR="${D}" SRCDIR="${B}" PACKAGE_ARCH="${PACKAGE_ARCH}" install
+}
+
+do_install_append() {
+ ln -nfs libMali.so ${D}${libdir}/libMali.so.1
+
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so.1
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so.1.0.0
+ ln -nfs libMali.so ${D}${libdir}/libEGL.so.1.4
+
+ ln -nfs libMali.so ${D}${libdir}/libgbm.so
+ ln -nfs libMali.so ${D}${libdir}/libgbm.so.1
+ ln -nfs libMali.so ${D}${libdir}/libgbm.so.1.0.0
+
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so.1
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so.1.1
+ ln -nfs libMali.so ${D}${libdir}/libGLESv1_CM.so.1.1.0
+
+ ln -nfs libMali.so ${D}${libdir}/libGLESv2.so
+ ln -nfs libMali.so ${D}${libdir}/libGLESv2.so.2
+ ln -nfs libMali.so ${D}${libdir}/libGLESv2.so.2.0.0
+
+ ln -nfs libMali.so ${D}${libdir}/libwayland-egl.so
+ ln -nfs libMali.so ${D}${libdir}/libwayland-egl.so.1
+ ln -nfs libMali.so ${D}${libdir}/libwayland-egl.so.1.0.0
+}
+
+RDEPENDS_${PN}-dev = ""
+
+FILES_${PN} = "${libdir}/libMali.so* \
+ ${libdir}/libGLESv2.so* \
+ ${libdir}/libEGL.so* \
+ ${libdir}/libgbm.so* \
+ ${libdir}/libGLESv1_CM.so* \
+ ${libdir}/libwayland-egl.so* "
+
+FILES_${PN}-dev = "${libdir}/libMali.la \
+ ${libdir}/libEGL.la \
+ ${libdir}/pkgconfig/egl.pc \
+ ${includedir}/EGL/eglextchromium.h \
+ ${includedir}/EGL/eglext.h \
+ ${includedir}/EGL/egl.h \
+ ${includedir}/EGL/eglmesaext.h \
+ ${includedir}/EGL/eglplatform.h \
+ ${libdir}/libgbm.la \
+ ${libdir}/pkgconfig/gbm.pc \
+ ${includedir}/gbm.h \
+ ${libdir}/libGLESv2.la \
+ ${libdir}/pkgconfig/glesv2.pc \
+ ${includedir}/GLES2/gl2ext.h \
+ ${includedir}/GLES2/gl2.h \
+ ${includedir}/GLES2/gl2platform.h \
+ ${includedir}/GLES3/gl3ext.h \
+ ${libdir}/libGLESv1_CM.la \
+ ${libdir}/pkgconfig/glesv1_cm.pc \
+ ${includedir}/GLES/egl.h \
+ ${includedir}/GLES/glext.h \
+ ${includedir}/GLES/gl.h \
+ ${includedir}/GLES/glplatform.h \
+ ${libdir}/libwayland-egl.la \
+ ${libdir}/pkgconfig/wayland-egl.pc \
+ ${includedir}/KHR/khrplatform.h"
+
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+INSANE_SKIP_${PN} += "dev-so"
+INSANE_SKIP_${PN} += "dev-deps"
+INSANE_SKIP_${PN} += "already-stripped"
+
diff --git a/meta/meta-mediatek/recipes-graphics/mesa/mesa_%.bbappend b/meta/meta-mediatek/recipes-graphics/mesa/mesa_%.bbappend
new file mode 100644
index 0000000..8bf893a
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/mesa/mesa_%.bbappend
@@ -0,0 +1,4 @@
+PACKAGECONFIG_remove_mt2701 = "egl gles"
+PROVIDES_remove_mt2701 = "virtual/libgles1 virtual/libgles2 virtual/egl virtual/libgl virtual/mesa"
+PACKAGECONFIG_remove_mt8173p1v2 = "egl gles"
+PROVIDES_remove_mt8173p1v2 = "virtual/libgles1 virtual/libgles2 virtual/egl virtual/libgl virtual/mesa"
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston-init.bbappend b/meta/meta-mediatek/recipes-graphics/wayland/weston-init.bbappend
new file mode 100644
index 0000000..f38d928
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston-init.bbappend
@@ -0,0 +1,12 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+WESTONSTART ??= "/usr/bin/weston-launch -u root -- --idle-time=4294967 --tty=1"
+WESTONSTOP ??= "/usr/bin/killall -s KILL weston"
+
+do_install_append() {
+ sed -e 's,ExecStart=.*,ExecStart=${WESTONSTART},g' \
+ -e '/ExecStart/a\ExecStop=${WESTONSTOP}' \
+ -e '/EnvironmentFile/d' \
+ -i ${D}${systemd_system_unitdir}/weston.service
+}
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-PATCH-1-9-hmi-controller-use-output_w-h-instead-of-c.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-PATCH-1-9-hmi-controller-use-output_w-h-instead-of-c.patch
new file mode 100644
index 0000000..1a241ee
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-PATCH-1-9-hmi-controller-use-output_w-h-instead-of-c.patch
@@ -0,0 +1,55 @@
+From c9120f0c15f901f507c0c626b7225f4e93fca700 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 11:21:23 +0800
+Subject: [PATCH 1/8] [[PATCH 1/9] hmi-controller: use output_w/h instead of
+ current_mode_w/h
+
+make use of output->w/h instead of output->current_mode->w/h,
+ output->w/h have involve factor of transform and scale
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ ivi-shell/hmi-controller.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
+index a0e49ba..c4f106d 100644
+--- a/ivi-shell/hmi-controller.c
++++ b/ivi-shell/hmi-controller.c
+@@ -804,8 +804,8 @@ hmi_controller_create(struct weston_compositor *ec)
+ base_layer = MEM_ALLOC(1 * sizeof(struct hmi_controller_layer));
+ base_layer->x = 0;
+ base_layer->y = 0;
+- base_layer->width = output->current_mode->width;
+- base_layer->height = output->current_mode->height;
++ base_layer->width = output->width;
++ base_layer->height = output->height;
+ base_layer->id_layer =
+ hmi_ctrl->hmi_setting->base_layer_id +
+ (i * hmi_ctrl->hmi_setting->base_layer_id_offset);
+@@ -824,8 +824,8 @@ hmi_controller_create(struct weston_compositor *ec)
+ application_layer = MEM_ALLOC(1 * sizeof(struct hmi_controller_layer));
+ application_layer->x = 0;
+ application_layer->y = 0;
+- application_layer->width = output->current_mode->width;
+- application_layer->height = output->current_mode->height - panel_height;
++ application_layer->width = output->width;
++ application_layer->height = output->height - panel_height;
+ application_layer->id_layer =
+ hmi_ctrl->hmi_setting->application_layer_id +
+ (i * hmi_ctrl->hmi_setting->base_layer_id_offset);
+@@ -841,9 +841,9 @@ hmi_controller_create(struct weston_compositor *ec)
+ hmi_ctrl->workspace_background_layer.x = 0;
+ hmi_ctrl->workspace_background_layer.y = 0;
+ hmi_ctrl->workspace_background_layer.width =
+- output->current_mode->width;
++ output->width;
+ hmi_ctrl->workspace_background_layer.height =
+- output->current_mode->height - panel_height;
++ output->height - panel_height;
+
+ hmi_ctrl->workspace_background_layer.id_layer =
+ hmi_ctrl->hmi_setting->workspace_background_layer_id;
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-add-switch_config.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-add-switch_config.patch
new file mode 100644
index 0000000..3d011d6
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-add-switch_config.patch
@@ -0,0 +1,31 @@
+From 08f1aa62f0a5faa0dc8aaf082264b77d37f0610d Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Wed, 25 Sep 2019 19:14:50 +0800
+Subject: [PATCH] add switch_config
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ compositor/main.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/compositor/main.c b/compositor/main.c
+index 21c501c..64e4e30 100644
+--- a/compositor/main.c
++++ b/compositor/main.c
+@@ -2499,6 +2499,13 @@ int main(int argc, char *argv[])
+ goto out;
+ }
+
++
++ if (config_switch_global_create(wet.compositor) < 0) {
++ weston_log("fatal: failed to config_switch_global_create\n");
++ goto out;
++ }
++
++
+ weston_compositor_flush_heads_changed(wet.compositor);
+ if (wet.init_failed)
+ goto out;
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-hmi-controller-use-output_w-h-instead-of-current_mod.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-hmi-controller-use-output_w-h-instead-of-current_mod.patch
new file mode 100644
index 0000000..d7f23a3
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0001-hmi-controller-use-output_w-h-instead-of-current_mod.patch
@@ -0,0 +1,58 @@
+From 05da7cf21de58425828099100358cddab67d2f6f Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Fri, 20 Apr 2018 10:49:48 +0800
+Subject: [PATCH 1/9] hmi-controller: use output_w/h instead of
+ current_mode_w/h
+
+make use of output->w/h instead of output->current_mode->w/h,
+output->w/h have involve factor of transform and scale
+Test: tesk ok
+
+Change-Id: Icd902acef813c1674020cf2af2352388539f9e37
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ ivi-shell/hmi-controller.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
+index 7b2f270..e47b499 100644
+--- a/ivi-shell/hmi-controller.c
++++ b/ivi-shell/hmi-controller.c
+@@ -802,8 +802,8 @@ hmi_controller_create(struct weston_compositor *ec)
+ base_layer = MEM_ALLOC(1 * sizeof(struct hmi_controller_layer));
+ base_layer->x = 0;
+ base_layer->y = 0;
+- base_layer->width = output->current_mode->width;
+- base_layer->height = output->current_mode->height;
++ base_layer->width = output->width;
++ base_layer->height = output->height;
+ base_layer->id_layer =
+ hmi_ctrl->hmi_setting->base_layer_id +
+ (i * hmi_ctrl->hmi_setting->base_layer_id_offset);
+@@ -822,8 +822,8 @@ hmi_controller_create(struct weston_compositor *ec)
+ application_layer = MEM_ALLOC(1 * sizeof(struct hmi_controller_layer));
+ application_layer->x = 0;
+ application_layer->y = 0;
+- application_layer->width = output->current_mode->width;
+- application_layer->height = output->current_mode->height - panel_height;
++ application_layer->width = output->width;
++ application_layer->height = output->height - panel_height;
+ application_layer->id_layer =
+ hmi_ctrl->hmi_setting->application_layer_id +
+ (i * hmi_ctrl->hmi_setting->base_layer_id_offset);
+@@ -839,9 +839,9 @@ hmi_controller_create(struct weston_compositor *ec)
+ hmi_ctrl->workspace_background_layer.x = 0;
+ hmi_ctrl->workspace_background_layer.y = 0;
+ hmi_ctrl->workspace_background_layer.width =
+- output->current_mode->width;
++ output->width;
+ hmi_ctrl->workspace_background_layer.height =
+- output->current_mode->height - panel_height;
++ output->height - panel_height;
+
+ hmi_ctrl->workspace_background_layer.id_layer =
+ hmi_ctrl->hmi_setting->workspace_background_layer_id;
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0002-PATCH-2-9-libinput-fix-issue-for-touch_event-cause-w.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0002-PATCH-2-9-libinput-fix-issue-for-touch_event-cause-w.patch
new file mode 100644
index 0000000..cf86044
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0002-PATCH-2-9-libinput-fix-issue-for-touch_event-cause-w.patch
@@ -0,0 +1,40 @@
+From 4ba125216b900fc57c63a915fb194c48f4b516c4 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 11:26:20 +0800
+Subject: [PATCH 2/8] [PATCH 2/9] libinput: fix issue for touch_event cause
+ weston crash
+
+1.fix touch_event cause weston crash
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ libweston/libinput-device.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/libweston/libinput-device.c b/libweston/libinput-device.c
+index e25df14..18a3032 100644
+--- a/libweston/libinput-device.c
++++ b/libweston/libinput-device.c
+@@ -436,6 +436,19 @@ handle_touch_with_coords(struct libinput_device *libinput_device,
+ x = libinput_event_touch_get_x_transformed(touch_event, width);
+ y = libinput_event_touch_get_y_transformed(touch_event, height);
+
++ if (x == 0)
++ x = x + 1;
++
++ if (y == 0)
++ y = y + 1;
++
++ if (x == wl_fixed_from_int(width))
++ x = x - 1;
++
++ if (y == wl_fixed_from_int(height))
++ y = y - 1;
++
++
+ weston_output_transform_coordinate(device->output,
+ x, y, &x, &y);
+
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0002-libinput-fix-issue-for-touch_event-cause-weston-cras.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0002-libinput-fix-issue-for-touch_event-cause-weston-cras.patch
new file mode 100644
index 0000000..85df381
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0002-libinput-fix-issue-for-touch_event-cause-weston-cras.patch
@@ -0,0 +1,41 @@
+From 411e213e6e87acf027a18cc4db38a27838352c0f Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Fri, 20 Apr 2018 10:51:51 +0800
+Subject: [PATCH 2/9] libinput: fix issue for touch_event cause weston crash
+
+1.fix touch_event cause weston crash
+Test: test ok
+
+Change-Id: I69bd82ef9c46e97392212b32d599c7fbb3fbb3f5
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ libweston/libinput-device.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/libweston/libinput-device.c b/libweston/libinput-device.c
+index f97afcf..031148c 100644
+--- a/libweston/libinput-device.c
++++ b/libweston/libinput-device.c
+@@ -312,6 +312,18 @@ handle_touch_with_coords(struct libinput_device *libinput_device,
+ x = libinput_event_touch_get_x_transformed(touch_event, width);
+ y = libinput_event_touch_get_y_transformed(touch_event, height);
+
++ if (x == 0)
++ x = x + 1;
++
++ if (y == 0)
++ y = y + 1;
++
++ if (x == wl_fixed_from_int(width))
++ x = x - 1;
++
++ if (y == wl_fixed_from_int(height))
++ y = y - 1;
++
+ weston_output_transform_coordinate(device->output,
+ x, y, &x, &y);
+
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0003-PATCH-3-9-compose-engine-turn-to-pixman-if-gl-init-f.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0003-PATCH-3-9-compose-engine-turn-to-pixman-if-gl-init-f.patch
new file mode 100644
index 0000000..13d3edb
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0003-PATCH-3-9-compose-engine-turn-to-pixman-if-gl-init-f.patch
@@ -0,0 +1,43 @@
+From 621569253b34788e096adda8132010d0a17d0844 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 11:31:09 +0800
+Subject: [PATCH 3/8] [PATCH 3/9] compose-engine: turn to pixman if gl init
+ fail
+
+if init_gl fail then turn to pixman to compose buffer
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ libweston/compositor-drm.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index 3891176..ef38a64 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -3921,6 +3921,7 @@ init_egl(struct drm_backend *b)
+
+ if (drm_backend_create_gl_renderer(b) < 0) {
+ gbm_device_destroy(b->gbm);
++ b->gbm = NULL;
+ return -1;
+ }
+
+@@ -6766,8 +6767,12 @@ drm_backend_create(struct weston_compositor *compositor,
+ }
+ } else {
+ if (init_egl(b) < 0) {
+- weston_log("failed to initialize egl\n");
+- goto err_udev_dev;
++ weston_log("failed to initialize egl, use pixman\n");
++ if (init_pixman(b) < 0) {
++ weston_log("failed to initialize pixman renderer\n");
++ goto err_udev_dev;
++ }
++ b->use_pixman = 1;
+ }
+ }
+
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0003-compose-engine-turn-to-pixman-if-gl-init-fail.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0003-compose-engine-turn-to-pixman-if-gl-init-fail.patch
new file mode 100644
index 0000000..a4bf921
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0003-compose-engine-turn-to-pixman-if-gl-init-fail.patch
@@ -0,0 +1,45 @@
+From 46cee2c18276062d45817fd38fedfa737f16f776 Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Fri, 20 Apr 2018 11:23:00 +0800
+Subject: [PATCH 3/9] compose-engine: turn to pixman if gl init fail
+
+if init_gl fail then turn to pixman to compose buffer
+Test: test ok
+
+Change-Id: I18979e4d6cc2d12e51bc12e7be581e919b3166e8
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ libweston/compositor-drm.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index 1d38f05..4a5cd67 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -1642,6 +1642,7 @@ init_egl(struct drm_backend *b)
+
+ if (drm_backend_create_gl_renderer(b) < 0) {
+ gbm_device_destroy(b->gbm);
++ b->gbm = NULL;
+ return -1;
+ }
+
+@@ -3261,8 +3262,12 @@ drm_backend_create(struct weston_compositor *compositor,
+ }
+ } else {
+ if (init_egl(b) < 0) {
+- weston_log("failed to initialize egl\n");
+- goto err_udev_dev;
++ weston_log("failed to initialize egl, use pixman\n");
++ if (init_pixman(b) < 0) {
++ weston_log("failed to initialize pixman renderer\n");
++ goto err_udev_dev;
++ }
++ b->use_pixman = 1;
+ }
+ }
+
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0004-PATCH-4-9-weston-do-not-check-master-fd-for-DRM-driv.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0004-PATCH-4-9-weston-do-not-check-master-fd-for-DRM-driv.patch
new file mode 100644
index 0000000..22093bb
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0004-PATCH-4-9-weston-do-not-check-master-fd-for-DRM-driv.patch
@@ -0,0 +1,31 @@
+From 264cd761cc03e2dd85e57a1162db73c4beec0d07 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 11:33:56 +0800
+Subject: [PATCH 4/8] [PATCH 4/9] weston: do not check master fd for DRM driver
+
+give access to other module to use drm.
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ libweston/launcher-direct.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/libweston/launcher-direct.c b/libweston/launcher-direct.c
+index e0ce6d6..fe76f51 100644
+--- a/libweston/launcher-direct.c
++++ b/libweston/launcher-direct.c
+@@ -231,11 +231,6 @@ launcher_direct_open(struct weston_launcher *launcher_base, const char *path, in
+
+ if (major(s.st_rdev) == DRM_MAJOR) {
+ launcher->drm_fd = fd;
+- if (!is_drm_master(fd)) {
+- weston_log("drm fd not master\n");
+- close(fd);
+- return -1;
+- }
+ }
+
+ return fd;
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0004-weston-do-not-check-master-fd-for-DRM-driver.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0004-weston-do-not-check-master-fd-for-DRM-driver.patch
new file mode 100644
index 0000000..cf319d6
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0004-weston-do-not-check-master-fd-for-DRM-driver.patch
@@ -0,0 +1,34 @@
+From af63d3bb90fac87b823112c5a7aac58848620ab0 Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Fri, 20 Apr 2018 13:29:58 +0800
+Subject: [PATCH 4/9] weston: do not check master fd for DRM driver
+
+give access to other module to use drm.
+Test: test ok
+
+Change-Id: I8dff3a2b9d7e21cb8a78fb6c0066a7befea05242
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ libweston/launcher-direct.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/libweston/launcher-direct.c b/libweston/launcher-direct.c
+index 8f16a69..2cf6c60 100644
+--- a/libweston/launcher-direct.c
++++ b/libweston/launcher-direct.c
+@@ -223,11 +223,6 @@ launcher_direct_open(struct weston_launcher *launcher_base, const char *path, in
+
+ if (major(s.st_rdev) == DRM_MAJOR) {
+ launcher->drm_fd = fd;
+- if (!is_drm_master(fd)) {
+- weston_log("drm fd not master\n");
+- close(fd);
+- return -1;
+- }
+ }
+
+ return fd;
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0005-PATCH-5-9-weston-install-client-protocol-to-sysroot-.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0005-PATCH-5-9-weston-install-client-protocol-to-sysroot-.patch
new file mode 100644
index 0000000..4fd683d
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0005-PATCH-5-9-weston-install-client-protocol-to-sysroot-.patch
@@ -0,0 +1,31 @@
+From 21f5f1844e02a50a8b1c2f9ddb39d01b34c92b0a Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 11:37:19 +0800
+Subject: [PATCH 5/8] [PATCH 5/9] weston: install client-protocol to sysroot
+ for other
+
+install *-protocol.c and *-client-protocol.h to sysroot.
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ Makefile.am | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 83bb253..769e103 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -292,7 +292,9 @@ libwestoninclude_HEADERS = \
+ libweston/timeline-object.h \
+ shared/matrix.h \
+ shared/config-parser.h \
+- shared/zalloc.h
++ shared/zalloc.h \
++ protocol/*-protocol.c \
++ protocol/*-client-protocol.h
+
+ libwestoninclude_HEADERS += \
+ libweston-desktop/libweston-desktop.h
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0005-weston-install-client-protocol-to-sysroot-for-other-.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0005-weston-install-client-protocol-to-sysroot-for-other-.patch
new file mode 100644
index 0000000..2503173
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0005-weston-install-client-protocol-to-sysroot-for-other-.patch
@@ -0,0 +1,34 @@
+From 5f18c3a9f28fe46b03135c10d389ca0f60fba218 Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Fri, 20 Apr 2018 13:34:51 +0800
+Subject: [PATCH 5/9] weston: install client-protocol to sysroot for other
+ modules access
+
+install *-protocol.c and *-client-protocol.h to sysroot.
+Test: test ok
+
+Change-Id: I621931a6eaa66689415dd5c3fa035326a8ee25a0
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ Makefile.am | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 89790d6..e23b03b 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -293,7 +293,9 @@ libwestoninclude_HEADERS = \
+ libweston/timeline-object.h \
+ shared/matrix.h \
+ shared/config-parser.h \
+- shared/zalloc.h
++ shared/zalloc.h \
++ protocol/*-protocol.c \
++ protocol/*-client-protocol.h
+
+ libwestoninclude_HEADERS += \
+ libweston-desktop/libweston-desktop.h
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0006-PATCH-7-9-weston-screen-shot-add-screen-shot.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0006-PATCH-7-9-weston-screen-shot-add-screen-shot.patch
new file mode 100644
index 0000000..19cb8e2
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0006-PATCH-7-9-weston-screen-shot-add-screen-shot.patch
@@ -0,0 +1,603 @@
+From 79d48c68d79e7436a045bb875e18f7e8c6829392 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 14:25:47 +0800
+Subject: [PATCH 6/8] [PATCH 7/9] weston-screen-shot: add screen shot
+
+add screen shot
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ Makefile.am | 26 +++-
+ clients/simple-screenshooter-mtk.c | 259 +++++++++++++++++++++++++++++++++++
+ libweston/compositor.c | 3 +
+ libweston/compositor.h | 3 +
+ libweston/pixel-formats.c | 2 +
+ libweston/weston-screenshooter-mtk.c | 129 +++++++++++++++++
+ protocol/weston-configure-mtk.xml | 67 +++++++++
+ 7 files changed, 486 insertions(+), 3 deletions(-)
+ create mode 100644 clients/simple-screenshooter-mtk.c
+ create mode 100644 libweston/weston-screenshooter-mtk.c
+ create mode 100644 protocol/weston-configure-mtk.xml
+
+diff --git a/Makefile.am b/Makefile.am
+index 769e103..a9e48f8 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -96,6 +96,7 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ libweston/linux-dmabuf.h \
+ libweston/pixel-formats.c \
+ libweston/pixel-formats.h \
++ libweston/weston-screenshooter-mtk.c \
+ shared/helpers.h \
+ shared/matrix.c \
+ shared/matrix.h \
+@@ -169,7 +170,10 @@ nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ protocol/input-timestamps-unstable-v1-protocol.c \
+ protocol/input-timestamps-unstable-v1-server-protocol.h \
+ protocol/weston-touch-calibration-protocol.c \
+- protocol/weston-touch-calibration-server-protocol.h
++ protocol/weston-touch-calibration-server-protocol.h \
++ protocol/pointer-constraints-unstable-v1-server-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-server-protocol.h
+
+ BUILT_SOURCES += $(nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES)
+
+@@ -652,6 +656,19 @@ weston_simple_dmabuf_v4l_CFLAGS = $(AM_CFLAGS) $(SIMPLE_DMABUF_V4L_CLIENT_CFLAGS
+ weston_simple_dmabuf_v4l_LDADD = $(SIMPLE_DMABUF_V4L_CLIENT_LIBS) libshared.la
+ endif
+
++demo_clients += weston-simple-screenshooter-mtk
++weston_simple_screenshooter_mtk_SOURCES = clients/simple-screenshooter-mtk.c
++nodist_weston_simple_screenshooter_mtk_SOURCES = \
++ protocol/xdg-shell-unstable-v6-protocol.c \
++ protocol/xdg-shell-unstable-v6-client-protocol.h \
++ protocol/fullscreen-shell-unstable-v1-protocol.c \
++ protocol/fullscreen-shell-unstable-v1-client-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-client-protocol.h
++weston_simple_screenshooter_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
++weston_simple_screenshooter_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
++
++
+ noinst_LTLIBRARIES += libtoytoolkit.la
+
+ libtoytoolkit_la_SOURCES = \
+@@ -911,7 +928,9 @@ BUILT_SOURCES += \
+ protocol/tablet-unstable-v2-protocol.c \
+ protocol/tablet-unstable-v2-client-protocol.h \
+ protocol/input-timestamps-unstable-v1-protocol.c \
+- protocol/input-timestamps-unstable-v1-client-protocol.h
++ protocol/input-timestamps-unstable-v1-client-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-client-protocol.h
+
+ westondatadir = $(datadir)/weston
+ dist_westondata_DATA = \
+@@ -1564,7 +1583,8 @@ EXTRA_DIST += \
+ protocol/weston-test.xml \
+ protocol/weston-touch-calibration.xml \
+ protocol/ivi-application.xml \
+- protocol/ivi-hmi-controller.xml
++ protocol/ivi-hmi-controller.xml \
++ protocol/weston-configure-mtk.xml
+
+ #
+ # manual test modules in tests subdirectory
+diff --git a/clients/simple-screenshooter-mtk.c b/clients/simple-screenshooter-mtk.c
+new file mode 100644
+index 0000000..cbca18b
+--- /dev/null
++++ b/clients/simple-screenshooter-mtk.c
+@@ -0,0 +1,259 @@
++/*
++ * Copyright © 2008 Kristian Høgsberg
++ *
++ * 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 <stdint.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <limits.h>
++#include <sys/param.h>
++#include <sys/mman.h>
++#include <cairo.h>
++
++#include <wayland-client.h>
++#include "weston-configure-mtk-client-protocol.h"
++#include "shared/os-compatibility.h"
++#include "shared/xalloc.h"
++
++/* The screenshooter is a good example of a custom object exposed by
++ * the compositor and serves as a test bed for implementing client
++ * side marshalling outside libwayland.so */
++
++static struct wl_shm *shm;
++static struct weston_screenshooter_mtk *mtk_screenshooter;
++static struct wl_list output_list;
++int min_x, min_y, max_x, max_y;
++int buffer_copy_done;
++
++struct screenshooter_output {
++ struct wl_output *output;
++ struct wl_buffer *buffer;
++ int width, height, offset_x, offset_y;
++ void *data;
++ struct wl_list link;
++};
++
++static void
++display_handle_geometry(void *data,
++ struct wl_output *wl_output,
++ int x,
++ int y,
++ int physical_width,
++ int physical_height,
++ int subpixel,
++ const char *make,
++ const char *model,
++ int transform)
++{
++ struct screenshooter_output *output;
++
++ output = wl_output_get_user_data(wl_output);
++
++ if (wl_output == output->output) {
++ output->offset_x = x;
++ output->offset_y = y;
++ }
++}
++
++static void
++display_handle_mode(void *data,
++ struct wl_output *wl_output,
++ uint32_t flags,
++ int width,
++ int height,
++ int refresh)
++{
++ struct screenshooter_output *output;
++
++ output = wl_output_get_user_data(wl_output);
++
++ if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT)) {
++ output->width = width;
++ output->height = height;
++ }
++}
++
++static const struct wl_output_listener output_listener = {
++ display_handle_geometry,
++ display_handle_mode
++};
++
++static void
++screenshooter_done(void *data, struct weston_screenshooter_mtk *mtk_screenshooter)
++{
++ fprintf(stderr, "screenshooter_done\n");
++ buffer_copy_done = 1;
++}
++
++static const struct weston_screenshooter_mtk_listener screenshooter_mtk_listener =
++{
++ screenshooter_done
++};
++
++static void
++handle_global(void *data, struct wl_registry *registry,
++ uint32_t name, const char *interface, uint32_t version)
++{
++ static struct screenshooter_output *output;
++
++ if (strcmp(interface, "wl_output") == 0) {
++ output = xmalloc(sizeof *output);
++ output->output = wl_registry_bind(registry, name,
++ &wl_output_interface, 1);
++ wl_list_insert(&output_list, &output->link);
++ wl_output_add_listener(output->output, &output_listener, output);
++ } else if (strcmp(interface, "wl_shm") == 0) {
++ shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
++ } else if (strcmp(interface, "weston_screenshooter_mtk") == 0) {
++ mtk_screenshooter = wl_registry_bind(registry, name,
++ &weston_screenshooter_mtk_interface,
++ 1);
++ }
++}
++
++static void
++handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
++{
++ /* XXX: unimplemented */
++}
++
++static const struct wl_registry_listener registry_listener = {
++ handle_global,
++ handle_global_remove
++};
++
++static struct wl_buffer *
++create_shm_buffer(int width, int height, void **data_out)
++{
++ struct wl_shm_pool *pool;
++ struct wl_buffer *buffer;
++ int fd, size, stride;
++ void *data;
++
++ stride = width * 4;
++ size = stride * height;
++
++ fd = os_create_anonymous_file(size);
++ if (fd < 0) {
++ fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
++ size);
++ return NULL;
++ }
++
++ data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
++ if (data == MAP_FAILED) {
++ fprintf(stderr, "mmap failed: %m\n");
++ close(fd);
++ return NULL;
++ }
++
++ pool = wl_shm_create_pool(shm, fd, size);
++ close(fd);
++ buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
++ WL_SHM_FORMAT_XRGB8888);
++ wl_shm_pool_destroy(pool);
++
++ *data_out = data;
++ fprintf(stderr,"create_shm_buffer\n");
++ return buffer;
++}
++
++static void
++usage(int error_code)
++{
++ fprintf(stderr, "Usage: simple-screenshooter-mtk [OPTIONS]\n\n"
++ " -m dump mainscreen\n"
++ " -s dump subscreen\n"
++ " -h This help text! default dump all screens\n\n");
++
++ exit(error_code);
++}
++
++int main(int argc, char *argv[])
++{
++ struct wl_display *display;
++ struct wl_registry *registry;
++ struct screenshooter_output *output;
++ int i, width, height;
++ int mainscreen=0;
++ int subscreen=0;
++ for (i = 1; i < argc; i++) {
++ if (strcmp("-m", argv[i]) == 0)
++ mainscreen = 1;
++ else if (strcmp("-s", argv[i]) == 0)
++ subscreen = 1;
++ else if (strcmp("-h", argv[i]) == 0)
++ usage(EXIT_SUCCESS);
++ else
++ usage(EXIT_SUCCESS);
++ }
++
++ display = wl_display_connect(NULL);
++ if (display == NULL) {
++ fprintf(stderr, "failed to create display: %m\n");
++ return -1;
++ }
++
++ wl_list_init(&output_list);
++ registry = wl_display_get_registry(display);
++ wl_registry_add_listener(registry, ®istry_listener, NULL);
++ wl_display_dispatch(display);
++ wl_display_roundtrip(display);
++ if (mtk_screenshooter == NULL) {
++ fprintf(stderr, "display doesn't support screenshooter\n");
++ return -1;
++ }
++
++ weston_screenshooter_mtk_add_listener(mtk_screenshooter,
++ &screenshooter_mtk_listener,
++ NULL);
++
++ wl_list_for_each_reverse(output, &output_list, link) {
++ if(mainscreen == 1) {
++ output->buffer = create_shm_buffer(1920, 1080, &output->data);
++ weston_screenshooter_mtk_shoot(mtk_screenshooter,output->output,output->buffer);
++ buffer_copy_done = 0;
++ while (!buffer_copy_done)
++ wl_display_roundtrip(display);
++
++ break;
++ }
++ else if(subscreen == 1) {
++ subscreen = 0;
++ }
++ else {
++ output->buffer = create_shm_buffer(1920, 1080, &output->data);
++ weston_screenshooter_mtk_shoot(mtk_screenshooter,output->output,output->buffer);
++ buffer_copy_done = 0;
++ while (!buffer_copy_done)
++ wl_display_roundtrip(display);
++ }
++ }
++ fprintf(stderr,"end!!!!!\n");
++ return 0;
++}
+diff --git a/libweston/compositor.c b/libweston/compositor.c
+index 9deb781..fdf5d25 100644
+--- a/libweston/compositor.c
++++ b/libweston/compositor.c
+@@ -2756,6 +2756,9 @@ weston_output_schedule_repaint(struct weston_output *output)
+ compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
+ return;
+
++ if(output->screenshoot_needed)
++ output->screenshoot_dump = 1;
++
+ if (!output->repaint_needed)
+ TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
+
+diff --git a/libweston/compositor.h b/libweston/compositor.h
+index 8b7a102..8736691 100644
+--- a/libweston/compositor.h
++++ b/libweston/compositor.h
+@@ -238,6 +238,9 @@ struct weston_output {
+ REPAINT_AWAITING_COMPLETION, /**< last repaint not yet finished */
+ } repaint_status;
+
++ int screenshoot_needed;
++ int screenshoot_dump;
++
+ /** If repaint_status is REPAINT_SCHEDULED, contains the time the
+ * next repaint should be run */
+ struct timespec next_repaint;
+diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c
+index df84a9f..b45db93 100644
+--- a/libweston/pixel-formats.c
++++ b/libweston/pixel-formats.c
+@@ -145,6 +145,8 @@ static const struct pixel_format_info pixel_format_table[] = {
+ },
+ {
+ .format = DRM_FORMAT_RGB888,
++ .depth = 24,
++ .bpp = 24,
+ },
+ {
+ .format = DRM_FORMAT_BGR888,
+diff --git a/libweston/weston-screenshooter-mtk.c b/libweston/weston-screenshooter-mtk.c
+new file mode 100644
+index 0000000..7ad8f97
+--- /dev/null
++++ b/libweston/weston-screenshooter-mtk.c
+@@ -0,0 +1,129 @@
++/*
++ * Copyright © 2008-2011 Kristian Høgsberg
++ *
++ * 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 <stdio.h>
++#include <string.h>
++#include <linux/input.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <sys/uio.h>
++
++#include "compositor.h"
++#include "weston-configure-mtk-server-protocol.h"
++#include "shared/helpers.h"
++
++#include "wcap/wcap-decode.h"
++
++struct screenshooter {
++ struct weston_compositor *ec;
++ struct wl_global *global;
++ struct wl_client *client;
++ //struct weston_process process;
++ struct wl_listener destroy_listener;
++};
++
++struct screenshooter_frame_listener {
++ struct wl_listener listener;
++ struct weston_buffer *buffer;
++ weston_screenshooter_done_func_t done;
++ void *data;
++};
++
++static void
++weston_screenshooter_mtk_shoot(struct wl_client *client,
++ struct wl_resource *resource,
++ struct wl_resource *output_resource,
++ struct wl_resource *buffer_resource)
++{
++ struct weston_output *output =
++ wl_resource_get_user_data(output_resource);
++ struct weston_buffer *buffer =
++ weston_buffer_from_resource(buffer_resource);
++ weston_log("weston_screenshooter_mtk_shoot.\n");
++ output->screenshoot_needed = 1;
++ weston_output_schedule_repaint(output);
++ if (buffer == NULL) {
++ wl_resource_post_no_memory(resource);
++ return;
++ }
++
++ weston_screenshooter_mtk_send_done(resource);
++}
++
++static const struct weston_screenshooter_mtk_interface screenshooter_mtk_implementation = {
++ weston_screenshooter_mtk_shoot
++};
++
++static void
++bind_screenshooter_mtk(struct wl_client *client,
++ void *data, uint32_t version, uint32_t id)
++{
++ struct screenshooter *shooter = data;
++ struct wl_resource *resource;
++
++ resource = wl_resource_create(client,
++ &weston_screenshooter_mtk_interface, 1, id);
++
++ if (resource == NULL) {
++ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
++ "screenshooter failed: permission denied");
++ wl_client_post_no_memory(client);
++ return;
++ }
++
++ wl_resource_set_implementation(resource, &screenshooter_mtk_implementation,
++ data, NULL);
++}
++
++static void
++screenshooter_destroy(struct wl_listener *listener, void *data)
++{
++ struct screenshooter *shooter =
++ container_of(listener, struct screenshooter, destroy_listener);
++
++ wl_global_destroy(shooter->global);
++ free(shooter);
++}
++
++WL_EXPORT void
++screenshooter_mtk_create(struct weston_compositor *ec)
++{
++ struct screenshooter *shooter;
++
++ shooter = malloc(sizeof *shooter);
++ if (shooter == NULL)
++ return;
++
++ shooter->ec = ec;
++ shooter->global = wl_global_create(ec->wl_display,
++ &weston_screenshooter_mtk_interface, 1,
++ shooter, bind_screenshooter_mtk);
++
++ shooter->destroy_listener.notify = screenshooter_destroy;
++ wl_signal_add(&ec->destroy_signal, &shooter->destroy_listener);
++}
+diff --git a/protocol/weston-configure-mtk.xml b/protocol/weston-configure-mtk.xml
+new file mode 100644
+index 0000000..120e904
+--- /dev/null
++++ b/protocol/weston-configure-mtk.xml
+@@ -0,0 +1,67 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<protocol name="weston_configure_mtk">
++
++ <copyright>
++ Copyright (C) 2016 MediaTek
++
++ 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.
++ </copyright>
++
++ <interface name="weston_screenshooter_mtk" version="1">
++ <request name="shoot">
++ <arg name="output" type="object" interface="wl_output"/>
++ <arg name="buffer" type="object" interface="wl_buffer"/>
++ </request>
++ <event name="done">
++ </event>
++ </interface>
++
++ <interface name="config_switch_set" version="1">
++ <description summary="app interface for setting configure for the surface"/>
++
++ <request name="sprite_switch">
++ <description summary="setting the surface configure">
++ This set view matched with the surface to show in overlay plane if
++ overlay planes are available.Otherwise, it walk primary plane to
++ render, and then send to drm to show.
++ </description>
++ <arg name="sprite_switch" type="int"/>
++ </request>
++ </interface>
++
++ <interface name="config_switch" version="1">
++ <description summary="create app configure path for setting parameter">
++ This interface is exposed as a global singleton.
++ This interface is implemented by server, it mainly provide channel to allow
++ client to control some properties.
++ </description>
++
++ <request name="connect">
++ <description summary="connect to server for setting parameter">
++ This request gives client way to connect server.In fact, parameters set by
++ app all through wl_surface because this is only way can be transmit by app.
++ </description>
++ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
++ <arg name="id" type="new_id" interface="config_switch_set"/>
++ </request>
++ </interface>
++
++</protocol>
++
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0006-weston-porting-atomic-drm-from-weston4.0.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0006-weston-porting-atomic-drm-from-weston4.0.patch
new file mode 100644
index 0000000..e7c0f05
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0006-weston-porting-atomic-drm-from-weston4.0.patch
@@ -0,0 +1,6546 @@
+From 6ff0106dc3fc3e9e442d634cb8e5dc0ef792416b Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Fri, 20 Apr 2018 20:43:48 +0800
+Subject: [PATCH 6/9] weston: porting atomic drm from weston4.0
+
+porting atomic drm from weston4.0
+Test: build pass
+
+Change-Id: I37829d8a4815117d4b8bac8d2f8d21f666f83104
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ Makefile.am | 2 +
+ libweston/compositor-drm.c | 3922 +++++++++++++++++++++++++++++++--------
+ libweston/compositor-drm.h | 16 +-
+ libweston/compositor-fbdev.c | 5 +-
+ libweston/compositor-headless.c | 3 +-
+ libweston/compositor-rdp.c | 3 +-
+ libweston/compositor-wayland.c | 6 +-
+ libweston/compositor-x11.c | 6 +-
+ libweston/compositor.c | 177 +-
+ libweston/compositor.h | 59 +-
+ libweston/pixel-formats.c | 430 +++++
+ libweston/pixel-formats.h | 194 ++
+ shared/timespec-util.h | 184 ++
+ 13 files changed, 4221 insertions(+), 786 deletions(-)
+ create mode 100644 libweston/pixel-formats.c
+ create mode 100644 libweston/pixel-formats.h
+
+diff --git a/Makefile.am b/Makefile.am
+index e23b03b..238cd2f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -105,6 +105,8 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ libweston/timeline-object.h \
+ libweston/linux-dmabuf.c \
+ libweston/linux-dmabuf.h \
++ libweston/pixel-formats.c \
++ libweston/pixel-formats.h \
+ shared/helpers.h \
+ shared/matrix.c \
+ shared/matrix.h \
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index 4a5cd67..bba22b3 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -54,6 +54,7 @@
+ #include "gl-renderer.h"
+ #include "weston-egl-ext.h"
+ #include "pixman-renderer.h"
++#include "pixel-formats.h"
+ #include "libbacklight.h"
+ #include "libinput-seat.h"
+ #include "launcher-util.h"
+@@ -62,10 +63,16 @@
+ #include "linux-dmabuf.h"
+ #include "linux-dmabuf-unstable-v1-server-protocol.h"
+
++#define HAVE_DRM_ATOMIC
++
+ #ifndef DRM_CAP_TIMESTAMP_MONOTONIC
+ #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
+ #endif
+
++#ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES
++#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
++#endif
++
+ #ifndef DRM_CAP_CURSOR_WIDTH
+ #define DRM_CAP_CURSOR_WIDTH 0x8
+ #endif
+@@ -78,6 +85,139 @@
+ #define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
+ #endif
+
++/**
++ * Represents the values of an enum-type KMS property
++ */
++struct drm_property_enum_info {
++ const char *name; /**< name as string (static, not freed) */
++ bool valid; /**< true if value is supported; ignore if false */
++ uint64_t value; /**< raw value */
++};
++
++/**
++ * Holds information on a DRM property, including its ID and the enum
++ * values it holds.
++ *
++ * DRM properties are allocated dynamically, and maintained as DRM objects
++ * within the normal object ID space; they thus do not have a stable ID
++ * to refer to. This includes enum values, which must be referred to by
++ * integer values, but these are not stable.
++ *
++ * drm_property_info allows a cache to be maintained where Weston can use
++ * enum values internally to refer to properties, with the mapping to DRM
++ * ID values being maintained internally.
++ */
++struct drm_property_info {
++ const char *name; /**< name as string (static, not freed) */
++ uint32_t prop_id; /**< KMS property object ID */
++ unsigned int num_enum_values; /**< number of enum values */
++ struct drm_property_enum_info *enum_values; /**< array of enum values */
++};
++
++/**
++ * List of properties attached to DRM planes
++ */
++enum wdrm_plane_property {
++ WDRM_PLANE_TYPE = 0,
++ WDRM_PLANE_SRC_X,
++ WDRM_PLANE_SRC_Y,
++ WDRM_PLANE_SRC_W,
++ WDRM_PLANE_SRC_H,
++ WDRM_PLANE_CRTC_X,
++ WDRM_PLANE_CRTC_Y,
++ WDRM_PLANE_CRTC_W,
++ WDRM_PLANE_CRTC_H,
++ WDRM_PLANE_FB_ID,
++ WDRM_PLANE_CRTC_ID,
++ WDRM_PLANE__COUNT
++};
++
++/**
++ * Possible values for the WDRM_PLANE_TYPE property.
++ */
++enum wdrm_plane_type {
++ WDRM_PLANE_TYPE_PRIMARY = 0,
++ WDRM_PLANE_TYPE_CURSOR,
++ WDRM_PLANE_TYPE_OVERLAY,
++ WDRM_PLANE_TYPE__COUNT
++};
++
++static struct drm_property_enum_info plane_type_enums[] = {
++ [WDRM_PLANE_TYPE_PRIMARY] = {
++ .name = "Primary",
++ },
++ [WDRM_PLANE_TYPE_OVERLAY] = {
++ .name = "Overlay",
++ },
++ [WDRM_PLANE_TYPE_CURSOR] = {
++ .name = "Cursor",
++ },
++};
++
++static const struct drm_property_info plane_props[] = {
++ [WDRM_PLANE_TYPE] = {
++ .name = "type",
++ .enum_values = plane_type_enums,
++ .num_enum_values = WDRM_PLANE_TYPE__COUNT,
++ },
++ [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
++ [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
++ [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
++ [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
++ [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
++ [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
++ [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
++ [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
++ [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
++ [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
++};
++
++/**
++ * List of properties attached to a DRM connector
++ */
++enum wdrm_connector_property {
++ WDRM_CONNECTOR_EDID = 0,
++ WDRM_CONNECTOR_DPMS,
++ WDRM_CONNECTOR_CRTC_ID,
++ WDRM_CONNECTOR__COUNT
++};
++
++static const struct drm_property_info connector_props[] = {
++ [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
++ [WDRM_CONNECTOR_DPMS] = { .name = "DPMS" },
++ [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
++};
++
++/**
++ * List of properties attached to DRM CRTCs
++ */
++enum wdrm_crtc_property {
++ WDRM_CRTC_MODE_ID = 0,
++ WDRM_CRTC_ACTIVE,
++ WDRM_CRTC__COUNT
++};
++
++static const struct drm_property_info crtc_props[] = {
++ [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
++ [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
++};
++
++/**
++ * Mode for drm_output_state_duplicate.
++ */
++enum drm_output_state_duplicate_mode {
++ DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
++ DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
++};
++
++/**
++ * Mode for drm_pending_state_apply and co.
++ */
++enum drm_state_apply_mode {
++ DRM_STATE_APPLY_SYNC, /**< state fully processed */
++ DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
++};
++
+ struct drm_backend {
+ struct weston_backend base;
+ struct weston_compositor *compositor;
+@@ -103,14 +243,24 @@ struct drm_backend {
+ */
+ int min_width, max_width;
+ int min_height, max_height;
+- int no_addfb2;
+
+- struct wl_list sprite_list;
++ struct wl_list plane_list;
+ int sprites_are_broken;
+ int sprites_hidden;
+
++ void *repaint_data;
++
++ bool state_invalid;
++
++ /* Connector and CRTC IDs not used by any enabled output. */
++ struct wl_array unused_connectors;
++ struct wl_array unused_crtcs;
++
+ int cursors_are_broken;
+
++ bool universal_planes;
++ bool atomic_modeset;
++
+ int use_pixman;
+
+ struct udev_input input;
+@@ -118,23 +268,39 @@ struct drm_backend {
+ int32_t cursor_width;
+ int32_t cursor_height;
+
+- uint32_t connector;
++ uint32_t pageflip_timeout;
++
++ bool shutting_down;
+ };
+
+ struct drm_mode {
+ struct weston_mode base;
+ drmModeModeInfo mode_info;
++ uint32_t blob_id;
++};
++
++enum drm_fb_type {
++ BUFFER_INVALID = 0, /**< never used */
++ BUFFER_CLIENT, /**< directly sourced from client */
++ BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
++ BUFFER_GBM_SURFACE, /**< internal EGL rendering */
++ BUFFER_CURSOR, /**< internal cursor buffer */
+ };
+
+ struct drm_fb {
++ enum drm_fb_type type;
++
++ int refcnt;
++
+ uint32_t fb_id, stride, handle, size;
++ const struct pixel_format_info *format;
+ int width, height;
+ int fd;
+- int is_client_buffer;
+ struct weston_buffer_reference buffer_ref;
+
+ /* Used by gbm fbs */
+ struct gbm_bo *bo;
++ struct gbm_surface *gbm_surface;
+
+ /* Used by dumb fbs */
+ void *map;
+@@ -147,6 +313,95 @@ struct drm_edid {
+ char serial_number[13];
+ };
+
++/**
++ * Pending state holds one or more drm_output_state structures, collected from
++ * performing repaint. This pending state is transient, and only lives between
++ * beginning a repaint group and flushing the results: after flush, each
++ * output state will complete and be retired separately.
++ */
++struct drm_pending_state {
++ struct drm_backend *backend;
++ struct wl_list output_list;
++};
++
++/*
++ * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
++ * plus >= 1 each of encoder/connector/plane. Since everything but the planes
++ * is currently statically assigned per-output, we mainly use this to track
++ * plane state.
++ *
++ * pending_state is set when the output state is owned by a pending_state,
++ * i.e. when it is being constructed and has not yet been applied. When the
++ * output state has been applied, the owning pending_state is freed.
++ */
++struct drm_output_state {
++ struct drm_pending_state *pending_state;
++ struct drm_output *output;
++ struct wl_list link;
++ enum dpms_enum dpms;
++ struct wl_list plane_list;
++};
++
++/**
++ * Plane state holds the dynamic state for a plane: where it is positioned,
++ * and which buffer it is currently displaying.
++ *
++ * The plane state is owned by an output state, except when setting an initial
++ * state. See drm_output_state for notes on state object lifetime.
++ */
++struct drm_plane_state {
++ struct drm_plane *plane;
++ struct drm_output *output;
++ struct drm_output_state *output_state;
++
++ struct drm_fb *fb;
++
++ int32_t src_x, src_y;
++ uint32_t src_w, src_h;
++ int32_t dest_x, dest_y;
++ uint32_t dest_w, dest_h;
++
++ bool complete;
++
++ struct wl_list link; /* drm_output_state::plane_list */
++};
++
++/**
++ * A plane represents one buffer, positioned within a CRTC, and stacked
++ * relative to other planes on the same CRTC.
++ *
++ * Each CRTC has a 'primary plane', which use used to display the classic
++ * framebuffer contents, as accessed through the legacy drmModeSetCrtc
++ * call (which combines setting the CRTC's actual physical mode, and the
++ * properties of the primary plane).
++ *
++ * The cursor plane also has its own alternate legacy API.
++ *
++ * Other planes are used opportunistically to display content we do not
++ * wish to blit into the primary plane. These non-primary/cursor planes
++ * are referred to as 'sprites'.
++ */
++struct drm_plane {
++ struct weston_plane base;
++
++ struct drm_backend *backend;
++
++ enum wdrm_plane_type type;
++
++ uint32_t possible_crtcs;
++ uint32_t plane_id;
++ uint32_t count_formats;
++
++ struct drm_property_info props[WDRM_PLANE__COUNT];
++
++ /* The last state submitted to the kernel for this plane. */
++ struct drm_plane_state *state_cur;
++
++ struct wl_list link;
++
++ uint32_t formats[];
++};
++
+ struct drm_output {
+ struct weston_output base;
+ drmModeConnector *connector;
+@@ -154,26 +409,38 @@ struct drm_output {
+ uint32_t crtc_id; /* object ID to pass to DRM functions */
+ int pipe; /* index of CRTC in resource array / bitmasks */
+ uint32_t connector_id;
+- drmModeCrtcPtr original_crtc;
+ struct drm_edid edid;
+- drmModePropertyPtr dpms_prop;
+- uint32_t gbm_format;
+
+- enum dpms_enum dpms;
++ /* Holds the properties for the connector */
++ struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
++ /* Holds the properties for the CRTC */
++ struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
++
++ struct backlight *backlight;
+
+ int vblank_pending;
+ int page_flip_pending;
++ int atomic_complete_pending;
+ int destroy_pending;
+ int disable_pending;
++ int dpms_off_pending;
+
+- struct gbm_surface *gbm_surface;
+- struct gbm_bo *gbm_cursor_bo[2];
+- struct weston_plane cursor_plane;
+- struct weston_plane fb_plane;
++ struct drm_fb *gbm_cursor_fb[2];
++ struct drm_plane *cursor_plane;
+ struct weston_view *cursor_view;
+ int current_cursor;
+- struct drm_fb *current, *next;
+- struct backlight *backlight;
++
++ struct gbm_surface *gbm_surface;
++ uint32_t gbm_format;
++
++ /* Plane being displayed directly on the CRTC */
++ struct drm_plane *scanout_plane;
++
++ /* The last state submitted to the kernel for this CRTC. */
++ struct drm_output_state *state_cur;
++ /* The previously-submitted state, where the hardware has not
++ * yet acknowledged completion of state_cur. */
++ struct drm_output_state *state_last;
+
+ struct drm_fb *dumb[2];
+ pixman_image_t *image[2];
+@@ -182,36 +449,33 @@ struct drm_output {
+
+ struct vaapi_recorder *recorder;
+ struct wl_listener recorder_frame_listener;
+-};
+
+-/*
+- * An output has a primary display plane plus zero or more sprites for
+- * blending display contents.
+- */
+-struct drm_sprite {
+- struct wl_list link;
++ struct wl_event_source *pageflip_timer;
++};
+
+- struct weston_plane plane;
++static struct gl_renderer_interface *gl_renderer;
+
+- struct drm_fb *current, *next;
+- struct drm_output *output;
+- struct drm_backend *backend;
++static const char default_seat[] = "seat0";
+
+- uint32_t possible_crtcs;
+- uint32_t plane_id;
+- uint32_t count_formats;
++static void
++wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
++{
++ uint32_t *pos, *end;
+
+- int32_t src_x, src_y;
+- uint32_t src_w, src_h;
+- uint32_t dest_x, dest_y;
+- uint32_t dest_w, dest_h;
++ end = (uint32_t *) ((char *) array->data + array->size);
+
+- uint32_t formats[];
+-};
++ wl_array_for_each(pos, array) {
++ if (*pos != elm)
++ continue;
+
+-static struct gl_renderer_interface *gl_renderer;
++ array->size -= sizeof(*pos);
++ if (pos + 1 == end)
++ break;
+
+-static const char default_seat[] = "seat0";
++ memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
++ break;
++ }
++}
+
+ static inline struct drm_output *
+ to_drm_output(struct weston_output *base)
+@@ -225,16 +489,286 @@ to_drm_backend(struct weston_compositor *base)
+ return container_of(base->backend, struct drm_backend, base);
+ }
+
++static int
++pageflip_timeout(void *data) {
++ /*
++ * Our timer just went off, that means we're not receiving drm
++ * page flip events anymore for that output. Let's gracefully exit
++ * weston with a return value so devs can debug what's going on.
++ */
++ struct drm_output *output = data;
++ struct weston_compositor *compositor = output->base.compositor;
++
++ weston_log("Pageflip timeout reached on output %s, your "
++ "driver is probably buggy! Exiting.\n",
++ output->base.name);
++ weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
++
++ return 0;
++}
++
++/* Creates the pageflip timer. Note that it isn't armed by default */
++static int
++drm_output_pageflip_timer_create(struct drm_output *output)
++{
++ struct wl_event_loop *loop = NULL;
++ struct weston_compositor *ec = output->base.compositor;
++
++ loop = wl_display_get_event_loop(ec->wl_display);
++ assert(loop);
++ output->pageflip_timer = wl_event_loop_add_timer(loop,
++ pageflip_timeout,
++ output);
++
++ if (output->pageflip_timer == NULL) {
++ weston_log("creating drm pageflip timer failed: %m\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static inline struct drm_mode *
++to_drm_mode(struct weston_mode *base)
++{
++ return container_of(base, struct drm_mode, base);
++}
++
++/**
++ * Get the current value of a KMS property
++ *
++ * Given a drmModeObjectGetProperties return, as well as the drm_property_info
++ * for the target property, return the current value of that property,
++ * with an optional default. If the property is a KMS enum type, the return
++ * value will be translated into the appropriate internal enum.
++ *
++ * If the property is not present, the default value will be returned.
++ *
++ * @param info Internal structure for property to look up
++ * @param props Raw KMS properties for the target object
++ * @param def Value to return if property is not found
++ */
++static uint64_t
++drm_property_get_value(struct drm_property_info *info,
++ drmModeObjectPropertiesPtr props,
++ uint64_t def)
++{
++ unsigned int i;
++
++ if (info->prop_id == 0)
++ return def;
++
++ for (i = 0; i < props->count_props; i++) {
++ unsigned int j;
++
++ if (props->props[i] != info->prop_id)
++ continue;
++
++ /* Simple (non-enum) types can return the value directly */
++ if (info->num_enum_values == 0)
++ return props->prop_values[i];
++
++ /* Map from raw value to enum value */
++ for (j = 0; j < info->num_enum_values; j++) {
++ if (!info->enum_values[j].valid)
++ continue;
++ if (info->enum_values[j].value != props->prop_values[i])
++ continue;
++
++ return j;
++ }
++
++ /* We don't have a mapping for this enum; return default. */
++ break;
++ }
++
++ return def;
++}
++
++/**
++ * Cache DRM property values
++ *
++ * Update a per-object array of drm_property_info structures, given the
++ * DRM properties of the object.
++ *
++ * Call this every time an object newly appears (note that only connectors
++ * can be hotplugged), the first time it is seen, or when its status changes
++ * in a way which invalidates the potential property values (currently, the
++ * only case for this is connector hotplug).
++ *
++ * This updates the property IDs and enum values within the drm_property_info
++ * array.
++ *
++ * DRM property enum values are dynamic at runtime; the user must query the
++ * property to find out the desired runtime value for a requested string
++ * name. Using the 'type' field on planes as an example, there is no single
++ * hardcoded constant for primary plane types; instead, the property must be
++ * queried at runtime to find the value associated with the string "Primary".
++ *
++ * This helper queries and caches the enum values, to allow us to use a set
++ * of compile-time-constant enums portably across various implementations.
++ * The values given in enum_names are searched for, and stored in the
++ * same-indexed field of the map array.
++ *
++ * @param b DRM backend object
++ * @param src DRM property info array to source from
++ * @param info DRM property info array to copy into
++ * @param num_infos Number of entries in the source array
++ * @param props DRM object properties for the object
++ */
++static void
++drm_property_info_populate(struct drm_backend *b,
++ const struct drm_property_info *src,
++ struct drm_property_info *info,
++ unsigned int num_infos,
++ drmModeObjectProperties *props)
++{
++ drmModePropertyRes *prop;
++ unsigned i, j;
++
++ for (i = 0; i < num_infos; i++) {
++ unsigned int j;
++
++ info[i].name = src[i].name;
++ info[i].prop_id = 0;
++ info[i].num_enum_values = src[i].num_enum_values;
++
++ if (src[i].num_enum_values == 0)
++ continue;
++
++ info[i].enum_values =
++ malloc(src[i].num_enum_values *
++ sizeof(*info[i].enum_values));
++ assert(info[i].enum_values);
++ for (j = 0; j < info[i].num_enum_values; j++) {
++ info[i].enum_values[j].name = src[i].enum_values[j].name;
++ info[i].enum_values[j].valid = false;
++ }
++ }
++
++ for (i = 0; i < props->count_props; i++) {
++ unsigned int k;
++
++ prop = drmModeGetProperty(b->drm.fd, props->props[i]);
++ if (!prop)
++ continue;
++
++ for (j = 0; j < num_infos; j++) {
++ if (!strcmp(prop->name, info[j].name))
++ break;
++ }
++
++ /* We don't know/care about this property. */
++ if (j == num_infos) {
++#ifdef DEBUG
++ weston_log("DRM debug: unrecognized property %u '%s'\n",
++ prop->prop_id, prop->name);
++#endif
++ drmModeFreeProperty(prop);
++ continue;
++ }
++
++ if (info[j].num_enum_values == 0 &&
++ (prop->flags & DRM_MODE_PROP_ENUM)) {
++ weston_log("DRM: expected property %s to not be an"
++ " enum, but it is; ignoring\n", prop->name);
++ drmModeFreeProperty(prop);
++ continue;
++ }
++
++ info[j].prop_id = props->props[i];
++
++ if (info[j].num_enum_values == 0) {
++ drmModeFreeProperty(prop);
++ continue;
++ }
++
++ if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
++ weston_log("DRM: expected property %s to be an enum,"
++ " but it is not; ignoring\n", prop->name);
++ drmModeFreeProperty(prop);
++ info[j].prop_id = 0;
++ continue;
++ }
++
++ for (k = 0; k < info[j].num_enum_values; k++) {
++ int l;
++
++ for (l = 0; l < prop->count_enums; l++) {
++ if (!strcmp(prop->enums[l].name,
++ info[j].enum_values[k].name))
++ break;
++ }
++
++ if (l == prop->count_enums)
++ continue;
++
++ info[j].enum_values[k].valid = true;
++ info[j].enum_values[k].value = prop->enums[l].value;
++ }
++
++ drmModeFreeProperty(prop);
++ }
++
++#ifdef DEBUG
++ for (i = 0; i < num_infos; i++) {
++ if (info[i].prop_id == 0)
++ weston_log("DRM warning: property '%s' missing\n",
++ info[i].name);
++ }
++#endif
++}
++
++/**
++ * Free DRM property information
++ *
++ * Frees all memory associated with a DRM property info array and zeroes
++ * it out, leaving it usable for a further drm_property_info_update() or
++ * drm_property_info_free().
++ *
++ * @param info DRM property info array
++ * @param num_props Number of entries in array to free
++ */
++static void
++drm_property_info_free(struct drm_property_info *info, int num_props)
++{
++ int i;
++
++ for (i = 0; i < num_props; i++)
++ free(info[i].enum_values);
++
++ memset(info, 0, sizeof(*info) * num_props);
++}
++
+ static void
+-drm_output_set_cursor(struct drm_output *output);
++drm_output_set_cursor(struct drm_output_state *output_state);
+
+ static void
+ drm_output_update_msc(struct drm_output *output, unsigned int seq);
+
+-static int
+-drm_sprite_crtc_supported(struct drm_output *output, struct drm_sprite *sprite)
++static void
++drm_output_destroy(struct weston_output *output_base);
++
++/**
++ * Returns true if the plane can be used on the given output for its current
++ * repaint cycle.
++ */
++static bool
++drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
+ {
+- return !!(sprite->possible_crtcs & (1 << output->pipe));
++ assert(plane->state_cur);
++
++ /* The plane still has a request not yet completed by the kernel. */
++ if (!plane->state_cur->complete)
++ return false;
++
++ /* The plane is still active on another output. */
++ if (plane->state_cur->output && plane->state_cur->output != output)
++ return false;
++
++ /* Check whether the plane can be used with this CRTC; possible_crtcs
++ * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
++ return !!(plane->possible_crtcs & (1 << output->pipe));
+ }
+
+ static struct drm_output *
+@@ -276,16 +810,39 @@ drm_output_find_by_connector(struct drm_backend *b, uint32_t connector_id)
+ }
+
+ static void
+-drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
++drm_fb_destroy(struct drm_fb *fb)
+ {
+- struct drm_fb *fb = data;
+-
+- if (fb->fb_id)
++ if (fb->fb_id != 0)
+ drmModeRmFB(fb->fd, fb->fb_id);
+-
+ weston_buffer_reference(&fb->buffer_ref, NULL);
++ free(fb);
++}
++
++static void
++drm_fb_destroy_dumb(struct drm_fb *fb)
++{
++ struct drm_mode_destroy_dumb destroy_arg;
+
+- free(data);
++ assert(fb->type == BUFFER_PIXMAN_DUMB);
++
++ if (fb->map && fb->size > 0)
++ munmap(fb->map, fb->size);
++
++ memset(&destroy_arg, 0, sizeof(destroy_arg));
++ destroy_arg.handle = fb->handle;
++ drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
++
++ drm_fb_destroy(fb);
++}
++
++static void
++drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
++{
++ struct drm_fb *fb = data;
++
++ assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
++ fb->type == BUFFER_CURSOR);
++ drm_fb_destroy(fb);
+ }
+
+ static struct drm_fb *
+@@ -294,30 +851,33 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
+ {
+ struct drm_fb *fb;
+ int ret;
+- uint32_t bpp, depth;
+
+ struct drm_mode_create_dumb create_arg;
+ struct drm_mode_destroy_dumb destroy_arg;
+ struct drm_mode_map_dumb map_arg;
++ uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
+
+ fb = zalloc(sizeof *fb);
+ if (!fb)
+ return NULL;
+
+- switch (format) {
+- case GBM_FORMAT_XRGB8888:
+- bpp = 32;
+- depth = 24;
+- break;
+- case GBM_FORMAT_RGB565:
+- bpp = depth = 16;
+- break;
+- default:
+- return NULL;
++ fb->refcnt = 1;
++
++ fb->format = pixel_format_get_info(format);
++ if (!fb->format) {
++ weston_log("failed to look up format 0x%lx\n",
++ (unsigned long) format);
++ goto err_fb;
++ }
++
++ if (!fb->format->depth || !fb->format->bpp) {
++ weston_log("format 0x%lx is not compatible with dumb buffers\n",
++ (unsigned long) format);
++ goto err_fb;
+ }
+
+ memset(&create_arg, 0, sizeof create_arg);
+- create_arg.bpp = bpp;
++ create_arg.bpp = fb->format->bpp;
+ create_arg.width = width;
+ create_arg.height = height;
+
+@@ -325,6 +885,7 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
+ if (ret)
+ goto err_fb;
+
++ fb->type = BUFFER_PIXMAN_DUMB;
+ fb->handle = create_arg.handle;
+ fb->stride = create_arg.pitch;
+ fb->size = create_arg.size;
+@@ -332,26 +893,15 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
+ fb->height = height;
+ fb->fd = b->drm.fd;
+
+- ret = -1;
+-
+- if (!b->no_addfb2) {
+- uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
+-
+- handles[0] = fb->handle;
+- pitches[0] = fb->stride;
+- offsets[0] = 0;
+-
+- ret = drmModeAddFB2(b->drm.fd, width, height,
+- format, handles, pitches, offsets,
+- &fb->fb_id, 0);
+- if (ret) {
+- weston_log("addfb2 failed: %m\n");
+- b->no_addfb2 = 1;
+- }
+- }
++ handles[0] = fb->handle;
++ pitches[0] = fb->stride;
++ offsets[0] = 0;
+
++ ret = drmModeAddFB2(b->drm.fd, width, height, fb->format->format,
++ handles, pitches, offsets, &fb->fb_id, 0);
+ if (ret) {
+- ret = drmModeAddFB(b->drm.fd, width, height, depth, bpp,
++ ret = drmModeAddFB(b->drm.fd, width, height,
++ fb->format->depth, fb->format->bpp,
+ fb->stride, fb->handle, &fb->fb_id);
+ }
+
+@@ -382,52 +932,50 @@ err_fb:
+ return NULL;
+ }
+
+-static void
+-drm_fb_destroy_dumb(struct drm_fb *fb)
++static struct drm_fb *
++drm_fb_ref(struct drm_fb *fb)
+ {
+- struct drm_mode_destroy_dumb destroy_arg;
+-
+- if (!fb->map)
+- return;
+-
+- if (fb->fb_id)
+- drmModeRmFB(fb->fd, fb->fb_id);
+-
+- weston_buffer_reference(&fb->buffer_ref, NULL);
+-
+- munmap(fb->map, fb->size);
+-
+- memset(&destroy_arg, 0, sizeof(destroy_arg));
+- destroy_arg.handle = fb->handle;
+- drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+-
+- free(fb);
++ fb->refcnt++;
++ return fb;
+ }
+
+ static struct drm_fb *
+-drm_fb_get_from_bo(struct gbm_bo *bo,
+- struct drm_backend *backend, uint32_t format)
++drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
++ uint32_t format, enum drm_fb_type type)
+ {
+ struct drm_fb *fb = gbm_bo_get_user_data(bo);
+ uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
+ int ret;
+
+- if (fb)
+- return fb;
++ if (fb) {
++ assert(fb->type == type);
++ return drm_fb_ref(fb);
++ }
++
++ assert(format != 0);
+
+ fb = zalloc(sizeof *fb);
+ if (fb == NULL)
+ return NULL;
+
++ fb->type = type;
++ fb->refcnt = 1;
+ fb->bo = bo;
+
+ fb->width = gbm_bo_get_width(bo);
+ fb->height = gbm_bo_get_height(bo);
+ fb->stride = gbm_bo_get_stride(bo);
+ fb->handle = gbm_bo_get_handle(bo).u32;
++ fb->format = pixel_format_get_info(format);
+ fb->size = fb->stride * fb->height;
+ fb->fd = backend->drm.fd;
+
++ if (!fb->format) {
++ weston_log("couldn't look up format 0x%lx\n",
++ (unsigned long) format);
++ goto err_free;
++ }
++
+ if (backend->min_width > fb->width ||
+ fb->width > backend->max_width ||
+ backend->min_height > fb->height ||
+@@ -436,33 +984,24 @@ drm_fb_get_from_bo(struct gbm_bo *bo,
+ goto err_free;
+ }
+
+- ret = -1;
+-
+- if (format && !backend->no_addfb2) {
+- handles[0] = fb->handle;
+- pitches[0] = fb->stride;
+- offsets[0] = 0;
++ handles[0] = fb->handle;
++ pitches[0] = fb->stride;
++ offsets[0] = 0;
+
+- ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
+- format, handles, pitches, offsets,
+- &fb->fb_id, 0);
+- if (ret) {
+- weston_log("addfb2 failed: %m\n");
+- backend->no_addfb2 = 1;
+- backend->sprites_are_broken = 1;
+- }
+- }
+-
+- if (ret)
++ ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
++ fb->format->format, handles, pitches, offsets,
++ &fb->fb_id, 0);
++ if (ret && fb->format->depth && fb->format->bpp)
+ ret = drmModeAddFB(backend->drm.fd, fb->width, fb->height,
+- 24, 32, fb->stride, fb->handle, &fb->fb_id);
++ fb->format->depth, fb->format->bpp,
++ fb->stride, fb->handle, &fb->fb_id);
+
+ if (ret) {
+ weston_log("failed to create kms fb: %m\n");
+ goto err_free;
+ }
+
+- gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
++ gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
+
+ return fb;
+
+@@ -475,28 +1014,496 @@ static void
+ drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
+ {
+ assert(fb->buffer_ref.buffer == NULL);
++ assert(fb->type == BUFFER_CLIENT);
++ weston_buffer_reference(&fb->buffer_ref, buffer);
++}
++
++static void
++drm_fb_unref(struct drm_fb *fb)
++{
++ if (!fb)
++ return;
++
++ assert(fb->refcnt > 0);
++ if (--fb->refcnt > 0)
++ return;
++
++ switch (fb->type) {
++ case BUFFER_PIXMAN_DUMB:
++ drm_fb_destroy_dumb(fb);
++ break;
++ case BUFFER_CURSOR:
++ case BUFFER_CLIENT:
++ gbm_bo_destroy(fb->bo);
++ break;
++ case BUFFER_GBM_SURFACE:
++ gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
++ break;
++ default:
++ assert(NULL);
++ break;
++ }
++}
++
++/**
++ * Allocate a new, empty, plane state.
++ */
++static struct drm_plane_state *
++drm_plane_state_alloc(struct drm_output_state *state_output,
++ struct drm_plane *plane)
++{
++ struct drm_plane_state *state = zalloc(sizeof(*state));
++
++ assert(state);
++ state->output_state = state_output;
++ state->plane = plane;
++
++ /* Here we only add the plane state to the desired link, and not
++ * set the member. Having an output pointer set means that the
++ * plane will be displayed on the output; this won't be the case
++ * when we go to disable a plane. In this case, it must be part of
++ * the commit (and thus the output state), but the member must be
++ * NULL, as it will not be on any output when the state takes
++ * effect.
++ */
++ if (state_output)
++ wl_list_insert(&state_output->plane_list, &state->link);
++ else
++ wl_list_init(&state->link);
++
++ return state;
++}
++
++/**
++ * Free an existing plane state. As a special case, the state will not
++ * normally be freed if it is the current state; see drm_plane_set_state.
++ */
++static void
++drm_plane_state_free(struct drm_plane_state *state, bool force)
++{
++ if (!state)
++ return;
++
++ wl_list_remove(&state->link);
++ wl_list_init(&state->link);
++ state->output_state = NULL;
++
++ if (force || state != state->plane->state_cur) {
++ drm_fb_unref(state->fb);
++ free(state);
++ }
++}
++
++/**
++ * Duplicate an existing plane state into a new plane state, storing it within
++ * the given output state. If the output state already contains a plane state
++ * for the drm_plane referenced by 'src', that plane state is freed first.
++ */
++static struct drm_plane_state *
++drm_plane_state_duplicate(struct drm_output_state *state_output,
++ struct drm_plane_state *src)
++{
++ struct drm_plane_state *dst = malloc(sizeof(*dst));
++ struct drm_plane_state *old, *tmp;
++
++ assert(src);
++ assert(dst);
++ *dst = *src;
++ wl_list_init(&dst->link);
++
++ wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
++ /* Duplicating a plane state into the same output state, so
++ * it can replace itself with an identical copy of itself,
++ * makes no sense. */
++ assert(old != src);
++ if (old->plane == dst->plane)
++ drm_plane_state_free(old, false);
++ }
++
++ wl_list_insert(&state_output->plane_list, &dst->link);
++ if (src->fb)
++ dst->fb = drm_fb_ref(src->fb);
++ dst->output_state = state_output;
++ dst->complete = false;
++
++ return dst;
++}
++
++/**
++ * Remove a plane state from an output state; if the plane was previously
++ * enabled, then replace it with a disabling state. This ensures that the
++ * output state was untouched from it was before the plane state was
++ * modified by the caller of this function.
++ *
++ * This is required as drm_output_state_get_plane may either allocate a
++ * new plane state, in which case this function will just perform a matching
++ * drm_plane_state_free, or it may instead repurpose an existing disabling
++ * state (if the plane was previously active), in which case this function
++ * will reset it.
++ */
++static void
++drm_plane_state_put_back(struct drm_plane_state *state)
++{
++ struct drm_output_state *state_output;
++ struct drm_plane *plane;
++
++ if (!state)
++ return;
++
++ state_output = state->output_state;
++ plane = state->plane;
++ drm_plane_state_free(state, false);
++
++ /* Plane was previously disabled; no need to keep this temporary
++ * state around. */
++ if (!plane->state_cur->fb)
++ return;
++
++ (void) drm_plane_state_alloc(state_output, plane);
++}
++
++/**
++ * Return a plane state from a drm_output_state.
++ */
++static struct drm_plane_state *
++drm_output_state_get_existing_plane(struct drm_output_state *state_output,
++ struct drm_plane *plane)
++{
++ struct drm_plane_state *ps;
++
++ wl_list_for_each(ps, &state_output->plane_list, link) {
++ if (ps->plane == plane)
++ return ps;
++ }
++
++ return NULL;
++}
++
++/**
++ * Return a plane state from a drm_output_state, either existing or
++ * freshly allocated.
++ */
++static struct drm_plane_state *
++drm_output_state_get_plane(struct drm_output_state *state_output,
++ struct drm_plane *plane)
++{
++ struct drm_plane_state *ps;
++
++ ps = drm_output_state_get_existing_plane(state_output, plane);
++ if (ps)
++ return ps;
++
++ return drm_plane_state_alloc(state_output, plane);
++}
++
++/**
++ * Allocate a new, empty drm_output_state. This should not generally be used
++ * in the repaint cycle; see drm_output_state_duplicate.
++ */
++static struct drm_output_state *
++drm_output_state_alloc(struct drm_output *output,
++ struct drm_pending_state *pending_state)
++{
++ struct drm_output_state *state = zalloc(sizeof(*state));
++
++ assert(state);
++ state->output = output;
++ state->dpms = WESTON_DPMS_OFF;
++ state->pending_state = pending_state;
++ if (pending_state)
++ wl_list_insert(&pending_state->output_list, &state->link);
++ else
++ wl_list_init(&state->link);
++
++ wl_list_init(&state->plane_list);
++
++ return state;
++}
++
++/**
++ * Duplicate an existing drm_output_state into a new one. This is generally
++ * used during the repaint cycle, to capture the existing state of an output
++ * and modify it to create a new state to be used.
++ *
++ * The mode determines whether the output will be reset to an a blank state,
++ * or an exact mirror of the current state.
++ */
++static struct drm_output_state *
++drm_output_state_duplicate(struct drm_output_state *src,
++ struct drm_pending_state *pending_state,
++ enum drm_output_state_duplicate_mode plane_mode)
++{
++ struct drm_output_state *dst = malloc(sizeof(*dst));
++ struct drm_plane_state *ps;
++
++ assert(dst);
++
++ /* Copy the whole structure, then individually modify the
++ * pending_state, as well as the list link into our pending
++ * state. */
++ *dst = *src;
++
++ dst->pending_state = pending_state;
++ if (pending_state)
++ wl_list_insert(&pending_state->output_list, &dst->link);
++ else
++ wl_list_init(&dst->link);
++
++ wl_list_init(&dst->plane_list);
++
++ wl_list_for_each(ps, &src->plane_list, link) {
++ /* Don't carry planes which are now disabled; these should be
++ * free for other outputs to reuse. */
++ if (!ps->output)
++ continue;
++
++ if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
++ (void) drm_plane_state_alloc(dst, ps->plane);
++ else
++ (void) drm_plane_state_duplicate(dst, ps);
++ }
++
++ return dst;
++}
++
++/**
++ * Free an unused drm_output_state.
++ */
++static void
++drm_output_state_free(struct drm_output_state *state)
++{
++ struct drm_plane_state *ps, *next;
++
++ if (!state)
++ return;
++
++ wl_list_for_each_safe(ps, next, &state->plane_list, link)
++ drm_plane_state_free(ps, false);
++
++ wl_list_remove(&state->link);
++
++ free(state);
++}
++
++/**
++ * Get output state to disable output
++ *
++ * Returns a pointer to an output_state object which can be used to disable
++ * an output (e.g. DPMS off).
++ *
++ * @param pending_state The pending state object owning this update
++ * @param output The output to disable
++ * @returns A drm_output_state to disable the output
++ */
++static struct drm_output_state *
++drm_output_get_disable_state(struct drm_pending_state *pending_state,
++ struct drm_output *output)
++{
++ struct drm_output_state *output_state;
++
++ output_state = drm_output_state_duplicate(output->state_cur,
++ pending_state,
++ DRM_OUTPUT_STATE_CLEAR_PLANES);
++ output_state->dpms = WESTON_DPMS_OFF;
++
++ return output_state;
++}
++
++/**
++ * Allocate a new drm_pending_state
++ *
++ * Allocate a new, empty, 'pending state' structure to be used across a
++ * repaint cycle or similar.
++ *
++ * @param backend DRM backend
++ * @returns Newly-allocated pending state structure
++ */
++static struct drm_pending_state *
++drm_pending_state_alloc(struct drm_backend *backend)
++{
++ struct drm_pending_state *ret;
++
++ ret = calloc(1, sizeof(*ret));
++ if (!ret)
++ return NULL;
++
++ ret->backend = backend;
++ wl_list_init(&ret->output_list);
++
++ return ret;
++}
++
++/**
++ * Free a drm_pending_state structure
++ *
++ * Frees a pending_state structure, as well as any output_states connected
++ * to this pending state.
++ *
++ * @param pending_state Pending state structure to free
++ */
++static void
++drm_pending_state_free(struct drm_pending_state *pending_state)
++{
++ struct drm_output_state *output_state, *tmp;
++
++ if (!pending_state)
++ return;
++
++ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
++ link) {
++ drm_output_state_free(output_state);
++ }
++
++ free(pending_state);
++}
++
++/**
++ * Find an output state in a pending state
++ *
++ * Given a pending_state structure, find the output_state for a particular
++ * output.
++ *
++ * @param pending_state Pending state structure to search
++ * @param output Output to find state for
++ * @returns Output state if present, or NULL if not
++ */
++static struct drm_output_state *
++drm_pending_state_get_output(struct drm_pending_state *pending_state,
++ struct drm_output *output)
++{
++ struct drm_output_state *output_state;
++
++ wl_list_for_each(output_state, &pending_state->output_list, link) {
++ if (output_state->output == output)
++ return output_state;
++ }
++
++ return NULL;
++}
++
++static int drm_pending_state_apply_sync(struct drm_pending_state *state);
++
++/**
++ * Mark a drm_output_state (the output's last state) as complete. This handles
++ * any post-completion actions such as updating the repaint timer, disabling the
++ * output, and finally freeing the state.
++ */
++static void
++drm_output_update_complete(struct drm_output *output, uint32_t flags,
++ unsigned int sec, unsigned int usec)
++{
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
++ struct drm_plane_state *ps;
++ struct timespec ts;
++
++ /* Stop the pageflip timer instead of rearming it here */
++ if (output->pageflip_timer)
++ wl_event_source_timer_update(output->pageflip_timer, 0);
++
++ wl_list_for_each(ps, &output->state_cur->plane_list, link)
++ ps->complete = true;
++
++ drm_output_state_free(output->state_last);
++ output->state_last = NULL;
++
++ if (output->destroy_pending) {
++ output->destroy_pending = 0;
++ output->disable_pending = 0;
++ output->dpms_off_pending = 0;
++ drm_output_destroy(&output->base);
++ return;
++ } else if (output->disable_pending) {
++ output->disable_pending = 0;
++ output->dpms_off_pending = 0;
++ weston_output_disable(&output->base);
++ return;
++ } else if (output->dpms_off_pending) {
++ struct drm_pending_state *pending = drm_pending_state_alloc(b);
++ output->dpms_off_pending = 0;
++ drm_output_get_disable_state(pending, output);
++ drm_pending_state_apply_sync(pending);
++ return;
++ } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
++ output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
++ /* DPMS can happen to us either in the middle of a repaint
++ * cycle (when we have painted fresh content, only to throw it
++ * away for DPMS off), or at any other random point. If the
++ * latter is true, then we cannot go through finish_frame,
++ * because the repaint machinery does not expect this. */
++ return;
++ }
++
++ ts.tv_sec = sec;
++ ts.tv_nsec = usec * 1000;
++ weston_output_finish_frame(&output->base, &ts, flags);
++
++ /* We can't call this from frame_notify, because the output's
++ * repaint needed flag is cleared just after that */
++ if (output->recorder)
++ weston_output_schedule_repaint(&output->base);
++}
++
++/**
++ * Mark an output state as current on the output, i.e. it has been
++ * submitted to the kernel. The mode argument determines whether this
++ * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
++ * or asynchronously (in which case we wait for events to complete).
++ */
++static void
++drm_output_assign_state(struct drm_output_state *state,
++ enum drm_state_apply_mode mode)
++{
++ struct drm_output *output = state->output;
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
++ struct drm_plane_state *plane_state;
++
++ assert(!output->state_last);
++
++ if (mode == DRM_STATE_APPLY_ASYNC)
++ output->state_last = output->state_cur;
++ else
++ drm_output_state_free(output->state_cur);
++
++ wl_list_remove(&state->link);
++ wl_list_init(&state->link);
++ state->pending_state = NULL;
++
++ output->state_cur = state;
++
++ if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC)
++ output->atomic_complete_pending = 1;
++
++ /* Replace state_cur on each affected plane with the new state, being
++ * careful to dispose of orphaned (but only orphaned) previous state.
++ * If the previous state is not orphaned (still has an output_state
++ * attached), it will be disposed of by freeing the output_state. */
++ wl_list_for_each(plane_state, &state->plane_list, link) {
++ struct drm_plane *plane = plane_state->plane;
++
++ if (plane->state_cur && !plane->state_cur->output_state)
++ drm_plane_state_free(plane->state_cur, true);
++ plane->state_cur = plane_state;
+
+- fb->is_client_buffer = 1;
++ if (mode != DRM_STATE_APPLY_ASYNC) {
++ plane_state->complete = true;
++ continue;
++ }
+
+- weston_buffer_reference(&fb->buffer_ref, buffer);
++ if (b->atomic_modeset)
++ continue;
++
++ if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
++ output->vblank_pending++;
++ else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
++ output->page_flip_pending = 1;
++ }
+ }
+
+-static void
+-drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
++static int
++drm_view_transform_supported(struct weston_view *ev)
+ {
+- if (!fb)
+- return;
+-
+- if (fb->map &&
+- (fb != output->dumb[0] && fb != output->dumb[1])) {
+- drm_fb_destroy_dumb(fb);
+- } else if (fb->bo) {
+- if (fb->is_client_buffer)
+- gbm_bo_destroy(fb->bo);
+- else
+- gbm_surface_release_buffer(output->gbm_surface,
+- fb->bo);
+- }
++ return !ev->transform.enabled ||
++ (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
+ }
+
+ static uint32_t
+@@ -530,36 +1537,61 @@ drm_output_check_scanout_format(struct drm_output *output,
+ }
+
+ static struct weston_plane *
+-drm_output_prepare_scanout_view(struct drm_output *output,
++drm_output_prepare_scanout_view(struct drm_output_state *output_state,
+ struct weston_view *ev)
+ {
++ struct drm_output *output = output_state->output;
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
++ struct drm_plane *scanout_plane = output->scanout_plane;
++ struct drm_plane_state *state;
+ struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+ struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+ struct gbm_bo *bo;
+ uint32_t format;
+
++ /* Don't import buffers which span multiple outputs. */
++ if (ev->output_mask != (1u << output->base.id))
++ return NULL;
++
+ /* We use GBM to import buffers. */
+ if (b->gbm == NULL)
+ return NULL;
+
+ if (buffer == NULL)
+ return NULL;
++ if (wl_shm_buffer_get(buffer->resource))
++ return NULL;
+
+ /* Make sure our view is exactly compatible with the output. */
+ if (ev->geometry.x != output->base.x ||
+ ev->geometry.y != output->base.y)
+ return NULL;
++ if (buffer->width != output->base.current_mode->width ||
++ buffer->height != output->base.current_mode->height)
++ return NULL;
++
+ if (ev->transform.enabled)
+ return NULL;
+ if (ev->geometry.scissor_enabled)
+ return NULL;
++ if (viewport->buffer.transform != output->base.transform)
++ return NULL;
++ if (viewport->buffer.scale != output->base.current_scale)
++ return NULL;
++ if (!drm_view_transform_supported(ev))
++ return NULL;
+
+- if (buffer->width != output->base.current_mode->width ||
+- buffer->height != output->base.current_mode->height)
++ if (ev->alpha != 1.0f)
+ return NULL;
+- if (viewport->buffer.transform != output->base.transform)
++
++ state = drm_output_state_get_plane(output_state, scanout_plane);
++ if (state->fb) {
++ /* If there is already a framebuffer on the scanout plane,
++ * a client view has already been placed on the scanout
++ * view. In that case, do not free or put back the state,
++ * but just leave it in place and quietly exit. */
+ return NULL;
++ }
+
+ bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+ buffer->resource, GBM_BO_USE_SCANOUT);
+@@ -570,26 +1602,42 @@ drm_output_prepare_scanout_view(struct drm_output *output,
+
+ format = drm_output_check_scanout_format(output, ev->surface, bo);
+ if (format == 0) {
++ drm_plane_state_put_back(state);
+ gbm_bo_destroy(bo);
+ return NULL;
+ }
+
+- output->next = drm_fb_get_from_bo(bo, b, format);
+- if (!output->next) {
++ state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
++ if (!state->fb) {
++ drm_plane_state_put_back(state);
+ gbm_bo_destroy(bo);
+ return NULL;
+ }
+
+- drm_fb_set_buffer(output->next, buffer);
++ drm_fb_set_buffer(state->fb, buffer);
++
++ state->output = output;
++
++ state->src_x = 0;
++ state->src_y = 0;
++ state->src_w = state->fb->width << 16;
++ state->src_h = state->fb->height << 16;
+
+- return &output->fb_plane;
++ state->dest_x = 0;
++ state->dest_y = 0;
++ state->dest_w = output->base.current_mode->width;
++ state->dest_h = output->base.current_mode->height;
++
++ return &scanout_plane->base;
+ }
+
+-static void
+-drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
++static struct drm_fb *
++drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
+ {
++ struct drm_output *output = state->output;
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
+ struct gbm_bo *bo;
++ struct drm_fb *ret;
+
+ output->base.compositor->renderer->repaint_output(&output->base,
+ damage);
+@@ -597,20 +1645,25 @@ drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
+ bo = gbm_surface_lock_front_buffer(output->gbm_surface);
+ if (!bo) {
+ weston_log("failed to lock front buffer: %m\n");
+- return;
++ return NULL;
+ }
+
+- output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
+- if (!output->next) {
++ ret = drm_fb_get_from_bo(bo, b, output->gbm_format, BUFFER_GBM_SURFACE);
++ if (!ret) {
+ weston_log("failed to get drm_fb for bo\n");
+ gbm_surface_release_buffer(output->gbm_surface, bo);
+- return;
++ return NULL;
+ }
++ ret->gbm_surface = output->gbm_surface;
++
++ return ret;
+ }
+
+-static void
+-drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
++static struct drm_fb *
++drm_output_render_pixman(struct drm_output_state *state,
++ pixman_region32_t *damage)
+ {
++ struct drm_output *output = state->output;
+ struct weston_compositor *ec = output->base.compositor;
+ pixman_region32_t total_damage, previous_damage;
+
+@@ -624,7 +1677,6 @@ drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
+
+ output->current_image ^= 1;
+
+- output->next = output->dumb[output->current_image];
+ pixman_renderer_output_set_buffer(&output->base,
+ output->image[output->current_image]);
+
+@@ -632,18 +1684,60 @@ drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
+
+ pixman_region32_fini(&total_damage);
+ pixman_region32_fini(&previous_damage);
++
++ return drm_fb_ref(output->dumb[output->current_image]);
+ }
+
+ static void
+-drm_output_render(struct drm_output *output, pixman_region32_t *damage)
++drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
+ {
++ struct drm_output *output = state->output;
+ struct weston_compositor *c = output->base.compositor;
++ struct drm_plane_state *scanout_state;
++ struct drm_plane *scanout_plane = output->scanout_plane;
+ struct drm_backend *b = to_drm_backend(c);
++ struct drm_fb *fb;
++
++ /* If we already have a client buffer promoted to scanout, then we don't
++ * want to render. */
++ scanout_state = drm_output_state_get_plane(state,
++ output->scanout_plane);
++ if (scanout_state->fb)
++ return;
++
++ if (!pixman_region32_not_empty(damage) &&
++ 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->width ==
++ output->base.current_mode->width &&
++ scanout_plane->state_cur->fb->height ==
++ output->base.current_mode->height) {
++ fb = drm_fb_ref(scanout_plane->state_cur->fb);
++ } else if (b->use_pixman) {
++ fb = drm_output_render_pixman(state, damage);
++ } else {
++ fb = drm_output_render_gl(state, damage);
++ }
++
++ if (!fb) {
++ drm_plane_state_put_back(scanout_state);
++ return;
++ }
++
++ scanout_state->fb = fb;
++ scanout_state->output = output;
++
++ scanout_state->src_x = 0;
++ scanout_state->src_y = 0;
++ 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 = scanout_state->src_w >> 16;
++ scanout_state->dest_h = scanout_state->src_h >> 16;
+
+- if (b->use_pixman)
+- drm_output_render_pixman(output, damage);
+- else
+- drm_output_render_gl(output, damage);
+
+ pixman_region32_subtract(&c->primary_plane.damage,
+ &c->primary_plane.damage, damage);
+@@ -661,8 +1755,6 @@ drm_output_set_gamma(struct weston_output *output_base,
+ /* check */
+ if (output_base->gamma_size != size)
+ return;
+- if (!output->original_crtc)
+- return;
+
+ rc = drmModeCrtcSetGamma(backend->drm.fd,
+ output->crtc_id,
+@@ -697,102 +1789,612 @@ drm_waitvblank_pipe(struct drm_output *output)
+ }
+
+ static int
+-drm_output_repaint(struct weston_output *output_base,
+- pixman_region32_t *damage)
++drm_output_apply_state_legacy(struct drm_output_state *state)
+ {
+- struct drm_output *output = to_drm_output(output_base);
+- struct drm_backend *backend =
+- to_drm_backend(output->base.compositor);
+- struct drm_sprite *s;
++ struct drm_output *output = state->output;
++ struct drm_backend *backend = to_drm_backend(output->base.compositor);
++ struct drm_plane *scanout_plane = output->scanout_plane;
++ struct drm_property_info *dpms_prop =
++ &output->props_conn[WDRM_CONNECTOR_DPMS];
++ struct drm_plane_state *scanout_state;
++ struct drm_plane_state *ps;
++ struct drm_plane *p;
+ struct drm_mode *mode;
++ struct timespec now;
+ int ret = 0;
+
+- if (output->disable_pending || output->destroy_pending)
+- return -1;
++ /* If disable_planes is set then assign_planes() wasn't
++ * called for this render, so we could still have a stale
++ * cursor plane set up.
++ */
++ if (output->base.disable_planes) {
++ output->cursor_view = NULL;
++ if (output->cursor_plane) {
++ output->cursor_plane->base.x = INT32_MIN;
++ output->cursor_plane->base.y = INT32_MIN;
++ }
++ }
+
+- if (!output->next)
+- drm_output_render(output, damage);
+- if (!output->next)
+- return -1;
++ if (state->dpms != WESTON_DPMS_ON) {
++ wl_list_for_each(ps, &state->plane_list, link) {
++ p = ps->plane;
++ assert(ps->fb == NULL);
++ assert(ps->output == NULL);
++
++ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
++ continue;
++
++ ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
++ if (ret)
++ weston_log("drmModeSetPlane failed disable: %m\n");
++ }
++
++ if (output->cursor_plane) {
++ ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
++ 0, 0, 0);
++ if (ret)
++ weston_log("drmModeSetCursor failed disable: %m\n");
++ }
++
++ ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
++ &output->connector_id, 0, NULL);
++ if (ret)
++ weston_log("drmModeSetCrtc failed disabling: %m\n");
++
++ drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
++ weston_compositor_read_presentation_clock(output->base.compositor, &now);
++ drm_output_update_complete(output,
++ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
++ now.tv_sec, now.tv_nsec / 1000);
++
++ return 0;
++ }
+
+- mode = container_of(output->base.current_mode, struct drm_mode, base);
+- if (!output->current ||
+- output->current->stride != output->next->stride) {
++ scanout_state =
++ drm_output_state_get_existing_plane(state, scanout_plane);
++
++ /* The legacy SetCrtc API doesn't allow us to do scaling, and the
++ * 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);
++
++ mode = to_drm_mode(output->base.current_mode);
++ if (backend->state_invalid || !scanout_plane->state_cur->fb ||
++ scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) {
+ ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
+- output->next->fb_id, 0, 0,
++ scanout_state->fb->fb_id,
++ 0, 0,
+ &output->connector_id, 1,
+ &mode->mode_info);
+ if (ret) {
+ weston_log("set mode failed: %m\n");
+- goto err_pageflip;
++ goto err;
+ }
+- output_base->set_dpms(output_base, WESTON_DPMS_ON);
+ }
+
+ if (drmModePageFlip(backend->drm.fd, output->crtc_id,
+- output->next->fb_id,
++ scanout_state->fb->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
+ weston_log("queueing pageflip failed: %m\n");
+- goto err_pageflip;
++ goto err;
+ }
+
+- output->page_flip_pending = 1;
++ assert(!output->page_flip_pending);
++
++ if (output->pageflip_timer)
++ wl_event_source_timer_update(output->pageflip_timer,
++ backend->pageflip_timeout);
+
+- drm_output_set_cursor(output);
++ drm_output_set_cursor(state);
+
+ /*
+ * Now, update all the sprite surfaces
+ */
+- wl_list_for_each(s, &backend->sprite_list, link) {
++ wl_list_for_each(ps, &state->plane_list, link) {
+ uint32_t flags = 0, fb_id = 0;
+ drmVBlank vbl = {
+ .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+ .request.sequence = 1,
+ };
+
+- if ((!s->current && !s->next) ||
+- !drm_sprite_crtc_supported(output, s))
+- continue;
++ p = ps->plane;
++ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
++ continue;
++
++ assert(p->state_cur->complete);
++ assert(!!p->state_cur->output == !!p->state_cur->fb);
++ assert(!p->state_cur->output || p->state_cur->output == output);
++ assert(!ps->complete);
++ assert(!ps->output || ps->output == output);
++ assert(!!ps->output == !!ps->fb);
++
++ if (ps->fb && !backend->sprites_hidden)
++ fb_id = ps->fb->fb_id;
++
++ ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
++ output->crtc_id, fb_id, flags,
++ ps->dest_x, ps->dest_y,
++ ps->dest_w, ps->dest_h,
++ ps->src_x, ps->src_y,
++ ps->src_w, ps->src_h);
++ if (ret)
++ weston_log("setplane failed: %d: %s\n",
++ ret, strerror(errno));
++
++ vbl.request.type |= drm_waitvblank_pipe(output);
++
++ /*
++ * Queue a vblank signal so we know when the surface
++ * becomes active on the display or has been replaced.
++ */
++ vbl.request.signal = (unsigned long) ps;
++ ret = drmWaitVBlank(backend->drm.fd, &vbl);
++ if (ret) {
++ weston_log("vblank event request failed: %d: %s\n",
++ ret, strerror(errno));
++ }
++ }
++
++ if (dpms_prop->prop_id && state->dpms != output->state_cur->dpms) {
++ ret = drmModeConnectorSetProperty(backend->drm.fd,
++ output->connector_id,
++ dpms_prop->prop_id,
++ state->dpms);
++ if (ret) {
++ weston_log("DRM: DPMS: failed property set for %s\n",
++ output->base.name);
++ }
++ }
++
++ drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
++
++ return 0;
++
++err:
++ output->cursor_view = NULL;
++ drm_output_state_free(state);
++ return -1;
++}
++
++#ifdef HAVE_DRM_ATOMIC
++static int
++crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
++ enum wdrm_crtc_property prop, uint64_t val)
++{
++ struct drm_property_info *info = &output->props_crtc[prop];
++ int ret;
++
++ if (info->prop_id == 0)
++ return -1;
++
++ ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
++ val);
++ return (ret <= 0) ? -1 : 0;
++}
++
++static int
++connector_add_prop(drmModeAtomicReq *req, struct drm_output *output,
++ enum wdrm_connector_property prop, uint64_t val)
++{
++ struct drm_property_info *info = &output->props_conn[prop];
++ int ret;
++
++ if (info->prop_id == 0)
++ return -1;
++
++ ret = drmModeAtomicAddProperty(req, output->connector_id,
++ info->prop_id, val);
++ return (ret <= 0) ? -1 : 0;
++}
++
++static int
++plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
++ enum wdrm_plane_property prop, uint64_t val)
++{
++ struct drm_property_info *info = &plane->props[prop];
++ int ret;
++
++ if (info->prop_id == 0)
++ return -1;
++
++ ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
++ val);
++ return (ret <= 0) ? -1 : 0;
++}
++
++static int
++drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
++{
++ int ret;
++
++ if (mode->blob_id)
++ return 0;
++
++ ret = drmModeCreatePropertyBlob(backend->drm.fd,
++ &mode->mode_info,
++ sizeof(mode->mode_info),
++ &mode->blob_id);
++ if (ret != 0)
++ weston_log("failed to create mode property blob: %m\n");
++
++ return ret;
++}
++
++static int
++drm_output_apply_state_atomic(struct drm_output_state *state,
++ drmModeAtomicReq *req,
++ uint32_t *flags)
++{
++ struct drm_output *output = state->output;
++ struct drm_backend *backend = to_drm_backend(output->base.compositor);
++ struct drm_plane_state *plane_state;
++ struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
++ int ret = 0;
++
++ if (state->dpms != output->state_cur->dpms)
++ *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
++
++ if (state->dpms == WESTON_DPMS_ON) {
++ ret = drm_mode_ensure_blob(backend, current_mode);
++ if (ret != 0)
++ return ret;
++
++ ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
++ current_mode->blob_id);
++ ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
++ ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
++ output->crtc_id);
++ } else {
++ ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
++ ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
++ ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
++ 0);
++ }
++
++ if (ret != 0) {
++ weston_log("couldn't set atomic CRTC/connector state\n");
++ return ret;
++ }
++
++ wl_list_for_each(plane_state, &state->plane_list, link) {
++ struct drm_plane *plane = plane_state->plane;
++
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
++ plane_state->fb ? plane_state->fb->fb_id : 0);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
++ plane_state->fb ? output->crtc_id : 0);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
++ plane_state->src_x);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
++ plane_state->src_y);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
++ plane_state->src_w);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
++ plane_state->src_h);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
++ plane_state->dest_x);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
++ plane_state->dest_y);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
++ plane_state->dest_w);
++ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
++ plane_state->dest_h);
++
++ if (ret != 0) {
++ weston_log("couldn't set plane state\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * Helper function used only by drm_pending_state_apply, with the same
++ * guarantees and constraints as that function.
++ */
++static int
++drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
++ enum drm_state_apply_mode mode)
++{
++ struct drm_backend *b = pending_state->backend;
++ struct drm_output_state *output_state, *tmp;
++ struct drm_plane *plane;
++ drmModeAtomicReq *req = drmModeAtomicAlloc();
++ uint32_t flags = 0;
++ int ret = 0;
++
++ if (!req)
++ return -1;
++
++ if (b->state_invalid) {
++ uint32_t *unused;
++ int err;
++
++ /* If we need to reset all our state (e.g. because we've
++ * just started, or just been VT-switched in), explicitly
++ * disable all the CRTCs and connectors we aren't using. */
++ wl_array_for_each(unused, &b->unused_connectors) {
++ struct drm_property_info infos[WDRM_CONNECTOR__COUNT];
++ struct drm_property_info *info;
++ drmModeObjectProperties *props;
++
++ memset(infos, 0, sizeof(infos));
++
++ props = drmModeObjectGetProperties(b->drm.fd,
++ *unused,
++ DRM_MODE_OBJECT_CONNECTOR);
++ if (!props) {
++ ret = -1;
++ continue;
++ }
++
++ drm_property_info_populate(b, connector_props, infos,
++ WDRM_CONNECTOR__COUNT,
++ props);
++ drmModeFreeObjectProperties(props);
++
++ info = &infos[WDRM_CONNECTOR_CRTC_ID];
++ err = drmModeAtomicAddProperty(req, *unused,
++ info->prop_id, 0);
++ if (err <= 0)
++ ret = -1;
++
++ info = &infos[WDRM_CONNECTOR_DPMS];
++ if (info->prop_id > 0)
++ err = drmModeAtomicAddProperty(req, *unused,
++ info->prop_id,
++ DRM_MODE_DPMS_OFF);
++ if (err <= 0)
++ ret = -1;
++
++ drm_property_info_free(infos, WDRM_CONNECTOR__COUNT);
++ }
++
++ wl_array_for_each(unused, &b->unused_crtcs) {
++ struct drm_property_info infos[WDRM_CRTC__COUNT];
++ struct drm_property_info *info;
++ drmModeObjectProperties *props;
++ uint64_t active;
++
++ memset(infos, 0, sizeof(infos));
++
++ /* We can't emit a disable on a CRTC that's already
++ * off, as the kernel will refuse to generate an event
++ * for an off->off state and fail the commit.
++ */
++ props = drmModeObjectGetProperties(b->drm.fd,
++ *unused,
++ DRM_MODE_OBJECT_CRTC);
++ if (!props) {
++ ret = -1;
++ continue;
++ }
++
++ drm_property_info_populate(b, crtc_props, infos,
++ WDRM_CRTC__COUNT,
++ props);
++
++ info = &infos[WDRM_CRTC_ACTIVE];
++ active = drm_property_get_value(info, props, 0);
++ drmModeFreeObjectProperties(props);
++ if (active == 0) {
++ drm_property_info_free(infos, WDRM_CRTC__COUNT);
++ continue;
++ }
++
++ err = drmModeAtomicAddProperty(req, *unused,
++ info->prop_id, 0);
++ if (err <= 0)
++ ret = -1;
++
++ info = &infos[WDRM_CRTC_MODE_ID];
++ err = drmModeAtomicAddProperty(req, *unused,
++ info->prop_id, 0);
++ if (err <= 0)
++ ret = -1;
++
++ drm_property_info_free(infos, WDRM_CRTC__COUNT);
++ }
++
++ /* Disable all the planes; planes which are being used will
++ * override this state in the output-state application. */
++ wl_list_for_each(plane, &b->plane_list, link) {
++ plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
++ plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
++ }
++
++ flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
++ }
++
++ wl_list_for_each(output_state, &pending_state->output_list, link) {
++ if (mode == DRM_STATE_APPLY_SYNC)
++ assert(output_state->dpms == WESTON_DPMS_OFF);
++ ret |= drm_output_apply_state_atomic(output_state, req, &flags);
++ }
++
++ if (ret != 0) {
++ weston_log("atomic: couldn't compile atomic state\n");
++ goto out;
++ }
++
++ switch (mode) {
++ case DRM_STATE_APPLY_SYNC:
++ break;
++ case DRM_STATE_APPLY_ASYNC:
++ flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
++ break;
++ }
++
++ ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
++ if (ret != 0) {
++ weston_log("atomic: couldn't commit new state: %m\n");
++ goto out;
++ }
++
++ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
++ link)
++ drm_output_assign_state(output_state, mode);
++
++ b->state_invalid = false;
++
++ assert(wl_list_empty(&pending_state->output_list));
++
++out:
++ drmModeAtomicFree(req);
++ drm_pending_state_free(pending_state);
++ return ret;
++}
++#endif
++
++/**
++ * Applies all of a pending_state asynchronously: the primary entry point for
++ * applying KMS state to a device. Updates the state for all outputs in the
++ * pending_state, as well as disabling any unclaimed outputs.
++ *
++ * Unconditionally takes ownership of pending_state, and clears state_invalid.
++ */
++static int
++drm_pending_state_apply(struct drm_pending_state *pending_state)
++{
++ struct drm_backend *b = pending_state->backend;
++ struct drm_output_state *output_state, *tmp;
++ uint32_t *unused;
++
++#ifdef HAVE_DRM_ATOMIC
++ if (b->atomic_modeset)
++ return drm_pending_state_apply_atomic(pending_state,
++ DRM_STATE_APPLY_ASYNC);
++#endif
++
++ if (b->state_invalid) {
++ /* If we need to reset all our state (e.g. because we've
++ * just started, or just been VT-switched in), explicitly
++ * disable all the CRTCs we aren't using. This also disables
++ * all connectors on these CRTCs, so we don't need to do that
++ * separately with the pre-atomic API. */
++ wl_array_for_each(unused, &b->unused_crtcs)
++ drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
++ NULL);
++ }
++
++ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
++ link) {
++ struct drm_output *output = output_state->output;
++ int ret;
++
++ ret = drm_output_apply_state_legacy(output_state);
++ if (ret != 0) {
++ weston_log("Couldn't apply state for output %s\n",
++ output->base.name);
++ }
++ }
++
++ b->state_invalid = false;
++
++ assert(wl_list_empty(&pending_state->output_list));
++
++ drm_pending_state_free(pending_state);
++
++ return 0;
++}
++
++/**
++ * The synchronous version of drm_pending_state_apply. May only be used to
++ * disable outputs. Does so synchronously: the request is guaranteed to have
++ * completed on return, and the output will not be touched afterwards.
++ *
++ * Unconditionally takes ownership of pending_state, and clears state_invalid.
++ */
++static int
++drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
++{
++ struct drm_backend *b = pending_state->backend;
++ struct drm_output_state *output_state, *tmp;
++ uint32_t *unused;
++
++#ifdef HAVE_DRM_ATOMIC
++ if (b->atomic_modeset)
++ return drm_pending_state_apply_atomic(pending_state,
++ DRM_STATE_APPLY_SYNC);
++#endif
++
++ if (b->state_invalid) {
++ /* If we need to reset all our state (e.g. because we've
++ * just started, or just been VT-switched in), explicitly
++ * disable all the CRTCs we aren't using. This also disables
++ * all connectors on these CRTCs, so we don't need to do that
++ * separately with the pre-atomic API. */
++ wl_array_for_each(unused, &b->unused_crtcs)
++ drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
++ NULL);
++ }
++
++ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
++ link) {
++ int ret;
++
++ assert(output_state->dpms == WESTON_DPMS_OFF);
++ ret = drm_output_apply_state_legacy(output_state);
++ if (ret != 0) {
++ weston_log("Couldn't apply state for output %s\n",
++ output_state->output->base.name);
++ }
++ }
++
++ b->state_invalid = false;
+
+- if (s->next && !backend->sprites_hidden)
+- fb_id = s->next->fb_id;
++ assert(wl_list_empty(&pending_state->output_list));
+
+- ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
+- output->crtc_id, fb_id, flags,
+- s->dest_x, s->dest_y,
+- s->dest_w, s->dest_h,
+- s->src_x, s->src_y,
+- s->src_w, s->src_h);
+- if (ret)
+- weston_log("setplane failed: %d: %s\n",
+- ret, strerror(errno));
++ drm_pending_state_free(pending_state);
+
+- vbl.request.type |= drm_waitvblank_pipe(output);
++ return 0;
++}
+
+- /*
+- * Queue a vblank signal so we know when the surface
+- * becomes active on the display or has been replaced.
+- */
+- vbl.request.signal = (unsigned long)s;
+- ret = drmWaitVBlank(backend->drm.fd, &vbl);
+- if (ret) {
+- weston_log("vblank event request failed: %d: %s\n",
+- ret, strerror(errno));
+- }
++static int
++drm_output_repaint(struct weston_output *output_base,
++ pixman_region32_t *damage,
++ void *repaint_data)
++{
++ struct drm_pending_state *pending_state = repaint_data;
++ struct drm_output *output = to_drm_output(output_base);
++ struct drm_output_state *state = NULL;
++ struct drm_plane_state *scanout_state;
+
+- s->output = output;
+- output->vblank_pending = 1;
+- }
++ if (output->disable_pending || output->destroy_pending)
++ goto err;
+
+- return 0;
++ assert(!output->state_last);
++
++ /* If planes have been disabled in the core, we might not have
++ * hit assign_planes at all, so might not have valid output state
++ * here. */
++ state = drm_pending_state_get_output(pending_state, output);
++ if (!state)
++ state = drm_output_state_duplicate(output->state_cur,
++ pending_state,
++ DRM_OUTPUT_STATE_CLEAR_PLANES);
++ state->dpms = WESTON_DPMS_ON;
++
++ drm_output_render(state, damage);
++ scanout_state = drm_output_state_get_plane(state,
++ output->scanout_plane);
++ if (!scanout_state || !scanout_state->fb)
++ goto err;
+
+-err_pageflip:
+- output->cursor_view = NULL;
+- if (output->next) {
+- drm_output_release_fb(output, output->next);
+- output->next = NULL;
+- }
++ return 0;
+
++err:
++ drm_output_state_free(state);
+ return -1;
+ }
+
+@@ -800,9 +2402,10 @@ static void
+ drm_output_start_repaint_loop(struct weston_output *output_base)
+ {
+ struct drm_output *output = to_drm_output(output_base);
++ struct drm_pending_state *pending_state;
++ struct drm_plane *scanout_plane = output->scanout_plane;
+ struct drm_backend *backend =
+ to_drm_backend(output_base->compositor);
+- uint32_t fb_id;
+ struct timespec ts, tnow;
+ struct timespec vbl2now;
+ int64_t refresh_nsec;
+@@ -816,11 +2419,19 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
+ if (output->disable_pending || output->destroy_pending)
+ return;
+
+- if (!output->current) {
++ if (!output->scanout_plane->state_cur->fb) {
+ /* We can't page flip if there's no mode set */
+ goto finish_frame;
+ }
+
++ /* Need to smash all state in from scratch; current timings might not
++ * be what we want, page flip might not work, etc.
++ */
++ if (backend->state_invalid)
++ goto finish_frame;
++
++ assert(scanout_plane->state_cur->output == output);
++
+ /* Try to get current msc and timestamp via instant query */
+ vbl.request.type |= drm_waitvblank_pipe(output);
+ ret = drmWaitVBlank(backend->drm.fd, &vbl);
+@@ -850,11 +2461,17 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
+ /* Immediate query didn't provide valid timestamp.
+ * Use pageflip fallback.
+ */
+- fb_id = output->current->fb_id;
+
+- if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
+- DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
+- weston_log("queueing pageflip failed: %m\n");
++ assert(!output->page_flip_pending);
++ assert(!output->state_last);
++
++ pending_state = drm_pending_state_alloc(backend);
++ drm_output_state_duplicate(output->state_cur, pending_state,
++ DRM_OUTPUT_STATE_PRESERVE_PLANES);
++
++ ret = drm_pending_state_apply(pending_state);
++ if (ret != 0) {
++ weston_log("applying repaint-start state failed: %m\n");
+ goto finish_frame;
+ }
+
+@@ -862,8 +2479,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
+
+ finish_frame:
+ /* if we cannot page-flip, immediately finish frame */
+- weston_compositor_read_presentation_clock(output_base->compositor, &ts);
+- weston_output_finish_frame(output_base, &ts,
++ weston_output_finish_frame(output_base, NULL,
+ WP_PRESENTATION_FEEDBACK_INVALID);
+ }
+
+@@ -882,70 +2498,132 @@ static void
+ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
+ void *data)
+ {
+- struct drm_sprite *s = (struct drm_sprite *)data;
+- struct drm_output *output = s->output;
+- struct timespec ts;
++ struct drm_plane_state *ps = (struct drm_plane_state *) data;
++ struct drm_output_state *os = ps->output_state;
++ struct drm_output *output = os->output;
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
+ uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
+ WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+
++ assert(!b->atomic_modeset);
++
+ drm_output_update_msc(output, frame);
+- output->vblank_pending = 0;
++ output->vblank_pending--;
++ assert(output->vblank_pending >= 0);
+
+- drm_output_release_fb(output, s->current);
+- s->current = s->next;
+- s->next = NULL;
++ assert(ps->fb);
+
+- if (!output->page_flip_pending) {
+- ts.tv_sec = sec;
+- ts.tv_nsec = usec * 1000;
+- weston_output_finish_frame(&output->base, &ts, flags);
+- }
+-}
++ if (output->page_flip_pending || output->vblank_pending)
++ return;
+
+-static void
+-drm_output_destroy(struct weston_output *base);
++ drm_output_update_complete(output, flags, sec, usec);
++}
+
+ static void
+ page_flip_handler(int fd, unsigned int frame,
+ unsigned int sec, unsigned int usec, void *data)
+ {
+ struct drm_output *output = data;
+- struct timespec ts;
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
+ uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
+ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
+ WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+
+ drm_output_update_msc(output, frame);
+
+- /* We don't set page_flip_pending on start_repaint_loop, in that case
+- * we just want to page flip to the current buffer to get an accurate
+- * timestamp */
+- if (output->page_flip_pending) {
+- drm_output_release_fb(output, output->current);
+- output->current = output->next;
+- output->next = NULL;
+- }
+-
++ assert(!b->atomic_modeset);
++ assert(output->page_flip_pending);
+ output->page_flip_pending = 0;
+
+- if (output->destroy_pending)
+- drm_output_destroy(&output->base);
+- else if (output->disable_pending)
+- weston_output_disable(&output->base);
+- else if (!output->vblank_pending) {
+- ts.tv_sec = sec;
+- ts.tv_nsec = usec * 1000;
+- weston_output_finish_frame(&output->base, &ts, flags);
++ if (output->vblank_pending)
++ return;
+
+- /* We can't call this from frame_notify, because the output's
+- * repaint needed flag is cleared just after that */
+- if (output->recorder)
+- weston_output_schedule_repaint(&output->base);
+- }
++ drm_output_update_complete(output, flags, sec, usec);
++}
++
++/**
++ * Begin a new repaint cycle
++ *
++ * Called by the core compositor at the beginning of a repaint cycle. Creates
++ * a new pending_state structure to own any output state created by individual
++ * output repaint functions until the repaint is flushed or cancelled.
++ */
++static void *
++drm_repaint_begin(struct weston_compositor *compositor)
++{
++ struct drm_backend *b = to_drm_backend(compositor);
++ struct drm_pending_state *ret;
++
++ ret = drm_pending_state_alloc(b);
++ b->repaint_data = ret;
++
++ return ret;
++}
++
++/**
++ * Flush a repaint set
++ *
++ * Called by the core compositor when a repaint cycle has been completed
++ * and should be flushed. Frees the pending state, transitioning ownership
++ * of the output state from the pending state, to the update itself. When
++ * the update completes (see drm_output_update_complete), the output
++ * state will be freed.
++ */
++static void
++drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
++{
++ struct drm_backend *b = to_drm_backend(compositor);
++ struct drm_pending_state *pending_state = repaint_data;
++
++ drm_pending_state_apply(pending_state);
++ b->repaint_data = NULL;
++}
++
++/**
++ * Cancel a repaint set
++ *
++ * Called by the core compositor when a repaint has finished, so the data
++ * held across the repaint cycle should be discarded.
++ */
++static void
++drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
++{
++ struct drm_backend *b = to_drm_backend(compositor);
++ struct drm_pending_state *pending_state = repaint_data;
++
++ drm_pending_state_free(pending_state);
++ b->repaint_data = NULL;
++}
++
++#ifdef HAVE_DRM_ATOMIC
++static void
++atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
++ unsigned int usec, unsigned int crtc_id, void *data)
++{
++ struct drm_backend *b = data;
++ struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
++ uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
++ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
++ WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
++
++ /* During the initial modeset, we can disable CRTCs which we don't
++ * actually handle during normal operation; this will give us events
++ * for unknown outputs. Ignore them. */
++ if (!output || !output->base.enabled)
++ return;
++
++ drm_output_update_msc(output, frame);
++
++ assert(b->atomic_modeset);
++ assert(output->atomic_complete_pending);
++ output->atomic_complete_pending = 0;
++
++ drm_output_update_complete(output, flags, sec, usec);
+ }
++#endif
+
+ static uint32_t
+-drm_output_check_sprite_format(struct drm_sprite *s,
++drm_output_check_plane_format(struct drm_plane *p,
+ struct weston_view *ev, struct gbm_bo *bo)
+ {
+ uint32_t i, format;
+@@ -966,31 +2644,25 @@ drm_output_check_sprite_format(struct drm_sprite *s,
+ pixman_region32_fini(&r);
+ }
+
+- for (i = 0; i < s->count_formats; i++)
+- if (s->formats[i] == format)
++ for (i = 0; i < p->count_formats; i++)
++ if (p->formats[i] == format)
+ return format;
+
+ return 0;
+ }
+
+-static int
+-drm_view_transform_supported(struct weston_view *ev)
+-{
+- return !ev->transform.enabled ||
+- (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
+-}
+-
+ static struct weston_plane *
+-drm_output_prepare_overlay_view(struct drm_output *output,
++drm_output_prepare_overlay_view(struct drm_output_state *output_state,
+ struct weston_view *ev)
+ {
++ struct drm_output *output = output_state->output;
+ struct weston_compositor *ec = output->base.compositor;
+ struct drm_backend *b = to_drm_backend(ec);
+ struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+ struct wl_resource *buffer_resource;
+- struct drm_sprite *s;
++ struct drm_plane *p;
++ struct drm_plane_state *state = NULL;
+ struct linux_dmabuf_buffer *dmabuf;
+- int found = 0;
+ struct gbm_bo *bo;
+ pixman_region32_t dest_rect, src_rect;
+ pixman_box32_t *box, tbox;
+@@ -1024,18 +2696,24 @@ drm_output_prepare_overlay_view(struct drm_output *output,
+ if (ev->alpha != 1.0f)
+ return NULL;
+
+- wl_list_for_each(s, &b->sprite_list, link) {
+- if (!drm_sprite_crtc_supported(output, s))
++ wl_list_for_each(p, &b->plane_list, link) {
++ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
+ continue;
+
+- if (!s->next) {
+- found = 1;
+- break;
++ if (!drm_plane_is_available(p, output))
++ continue;
++
++ state = drm_output_state_get_plane(output_state, p);
++ if (state->fb) {
++ state = NULL;
++ continue;
+ }
++
++ break;
+ }
+
+ /* No sprites available */
+- if (!found)
++ if (!state)
+ return NULL;
+
+ if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
+@@ -1072,32 +2750,30 @@ drm_output_prepare_overlay_view(struct drm_output *output,
+ bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
+ GBM_BO_USE_SCANOUT);
+ #else
+- return NULL;
++ goto err;
+ #endif
+ } else {
+ bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+ buffer_resource, GBM_BO_USE_SCANOUT);
+ }
+ if (!bo)
+- return NULL;
++ goto err;
+
+- format = drm_output_check_sprite_format(s, ev, bo);
+- if (format == 0) {
+- gbm_bo_destroy(bo);
+- return NULL;
+- }
++ format = drm_output_check_plane_format(p, ev, bo);
++ if (format == 0)
++ goto err;
+
+- s->next = drm_fb_get_from_bo(bo, b, format);
+- if (!s->next) {
+- gbm_bo_destroy(bo);
+- return NULL;
+- }
++ state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
++ if (!state->fb)
++ goto err;
++
++ drm_fb_set_buffer(state->fb, ev->surface->buffer_ref.buffer);
+
+- drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
++ state->output = output;
+
+ box = pixman_region32_extents(&ev->transform.boundingbox);
+- s->plane.x = box->x1;
+- s->plane.y = box->y1;
++ p->base.x = box->x1;
++ p->base.y = box->y1;
+
+ /*
+ * Calculate the source & dest rects properly based on actual
+@@ -1114,10 +2790,10 @@ drm_output_prepare_overlay_view(struct drm_output *output,
+ output->base.transform,
+ output->base.current_scale,
+ *box);
+- s->dest_x = tbox.x1;
+- s->dest_y = tbox.y1;
+- s->dest_w = tbox.x2 - tbox.x1;
+- s->dest_h = tbox.y2 - tbox.y1;
++ state->dest_x = tbox.x1;
++ state->dest_y = tbox.y1;
++ state->dest_w = tbox.x2 - tbox.x1;
++ state->dest_h = tbox.y2 - tbox.y1;
+ pixman_region32_fini(&dest_rect);
+
+ pixman_region32_init(&src_rect);
+@@ -1154,27 +2830,83 @@ drm_output_prepare_overlay_view(struct drm_output *output,
+ viewport->buffer.scale,
+ tbox);
+
+- s->src_x = tbox.x1 << 8;
+- s->src_y = tbox.y1 << 8;
+- s->src_w = (tbox.x2 - tbox.x1) << 8;
+- s->src_h = (tbox.y2 - tbox.y1) << 8;
++ state->src_x = tbox.x1 << 8;
++ state->src_y = tbox.y1 << 8;
++ state->src_w = (tbox.x2 - tbox.x1) << 8;
++ state->src_h = (tbox.y2 - tbox.y1) << 8;
+ pixman_region32_fini(&src_rect);
+
+- return &s->plane;
++ return &p->base;
++
++err:
++ drm_plane_state_put_back(state);
++ if (bo)
++ gbm_bo_destroy(bo);
++ return NULL;
++}
++
++/**
++ * Update the image for the current cursor surface
++ *
++ * @param b DRM backend structure
++ * @param bo GBM buffer object to write into
++ * @param ev View to use for cursor image
++ */
++static void
++cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
++ struct weston_view *ev)
++{
++ struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
++ uint32_t buf[b->cursor_width * b->cursor_height];
++ int32_t stride;
++ uint8_t *s;
++ int i;
++
++ assert(buffer && buffer->shm_buffer);
++ assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
++ assert(ev->surface->width <= b->cursor_width);
++ assert(ev->surface->height <= b->cursor_height);
++
++ memset(buf, 0, sizeof buf);
++ stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
++ s = wl_shm_buffer_get_data(buffer->shm_buffer);
++
++ wl_shm_buffer_begin_access(buffer->shm_buffer);
++ for (i = 0; i < ev->surface->height; i++)
++ memcpy(buf + i * b->cursor_width,
++ s + i * stride,
++ ev->surface->width * 4);
++ wl_shm_buffer_end_access(buffer->shm_buffer);
++
++ if (gbm_bo_write(bo, buf, sizeof buf) < 0)
++ weston_log("failed update cursor: %m\n");
+ }
+
+ static struct weston_plane *
+-drm_output_prepare_cursor_view(struct drm_output *output,
++drm_output_prepare_cursor_view(struct drm_output_state *output_state,
+ struct weston_view *ev)
+ {
++ struct drm_output *output = output_state->output;
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
++ struct drm_plane *plane = output->cursor_plane;
++ struct drm_plane_state *plane_state;
+ struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+ struct wl_shm_buffer *shmbuf;
++ bool needs_update = false;
++ float x, y;
+
++ if (!plane)
++ return NULL;
++
++#if 0
+ if (b->cursors_are_broken)
+ return NULL;
++#endif
++
++ if (!plane->state_cur->complete)
++ return NULL;
+
+- if (output->cursor_view)
++ if (plane->state_cur->output && plane->state_cur->output != output)
+ return NULL;
+
+ /* Don't import buffers which span multiple outputs. */
+@@ -1207,111 +2939,120 @@ drm_output_prepare_cursor_view(struct drm_output *output,
+ ev->surface->height > b->cursor_height)
+ return NULL;
+
+- output->cursor_view = ev;
+-
+- return &output->cursor_plane;
+-}
+-
+-/**
+- * Update the image for the current cursor surface
+- *
+- * @param b DRM backend structure
+- * @param bo GBM buffer object to write into
+- * @param ev View to use for cursor image
+- */
+-static void
+-cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
+- struct weston_view *ev)
+-{
+- struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+- uint32_t buf[b->cursor_width * b->cursor_height];
+- int32_t stride;
+- uint8_t *s;
+- int i;
+-
+- assert(buffer && buffer->shm_buffer);
+- assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
+- assert(ev->surface->width <= b->cursor_width);
+- assert(ev->surface->height <= b->cursor_height);
++ plane_state =
++ drm_output_state_get_plane(output_state, output->cursor_plane);
+
+- memset(buf, 0, sizeof buf);
+- stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+- s = wl_shm_buffer_get_data(buffer->shm_buffer);
++ if (plane_state && plane_state->fb)
++ return NULL;
+
+- wl_shm_buffer_begin_access(buffer->shm_buffer);
+- for (i = 0; i < ev->surface->height; i++)
+- memcpy(buf + i * b->cursor_width,
+- s + i * stride,
+- ev->surface->width * 4);
+- wl_shm_buffer_end_access(buffer->shm_buffer);
++ /* Since we're setting plane state up front, we need to work out
++ * whether or not we need to upload a new cursor. We can't use the
++ * plane damage, since the planes haven't actually been calculated
++ * yet: instead try to figure it out directly. KMS cursor planes are
++ * pretty unique here, in that they lie partway between a Weston plane
++ * (direct scanout) and a renderer. */
++ if (ev != output->cursor_view ||
++ pixman_region32_not_empty(&ev->surface->damage)) {
++ output->current_cursor++;
++ output->current_cursor =
++ output->current_cursor %
++ ARRAY_LENGTH(output->gbm_cursor_fb);
++ needs_update = true;
++ }
+
+- if (gbm_bo_write(bo, buf, sizeof buf) < 0)
+- weston_log("failed update cursor: %m\n");
++ output->cursor_view = ev;
++ weston_view_to_global_float(ev, 0, 0, &x, &y);
++ plane->base.x = x;
++ plane->base.y = y;
++
++ plane_state->fb =
++ drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
++ plane_state->output = output;
++ plane_state->src_x = 0;
++ plane_state->src_y = 0;
++ plane_state->src_w = b->cursor_width << 16;
++ plane_state->src_h = b->cursor_height << 16;
++ plane_state->dest_x = (x - output->base.x) * output->base.current_scale;
++ plane_state->dest_y = (y - output->base.y) * output->base.current_scale;
++ plane_state->dest_w = b->cursor_width;
++ plane_state->dest_h = b->cursor_height;
++
++ if (needs_update)
++ cursor_bo_update(b, plane_state->fb->bo, ev);
++
++ return &plane->base;
+ }
+
+ static void
+-drm_output_set_cursor(struct drm_output *output)
++drm_output_set_cursor(struct drm_output_state *output_state)
+ {
+- struct weston_view *ev = output->cursor_view;
+- struct weston_buffer *buffer;
++ struct drm_output *output = output_state->output;
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
++ struct drm_plane *plane = output->cursor_plane;
++ struct drm_plane_state *state;
+ EGLint handle;
+ struct gbm_bo *bo;
+- float x, y;
+
+- output->cursor_view = NULL;
+- if (ev == NULL) {
++ if (!plane)
++ return;
++
++ state = drm_output_state_get_existing_plane(output_state, plane);
++ if (!state)
++ return;
++
++ if (!state->fb) {
++ pixman_region32_fini(&plane->base.damage);
++ pixman_region32_init(&plane->base.damage);
+ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+- output->cursor_plane.x = INT32_MIN;
+- output->cursor_plane.y = INT32_MIN;
+ return;
+ }
+
+- buffer = ev->surface->buffer_ref.buffer;
+-
+- if (buffer &&
+- pixman_region32_not_empty(&output->cursor_plane.damage)) {
+- pixman_region32_fini(&output->cursor_plane.damage);
+- pixman_region32_init(&output->cursor_plane.damage);
+- output->current_cursor ^= 1;
+- bo = output->gbm_cursor_bo[output->current_cursor];
++ assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
++ assert(!plane->state_cur->output || plane->state_cur->output == output);
+
+- cursor_bo_update(b, bo, ev);
++ if (plane->state_cur->fb != state->fb) {
++ bo = state->fb->bo;
+ handle = gbm_bo_get_handle(bo).s32;
+ if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
+- b->cursor_width, b->cursor_height)) {
++ b->cursor_width, b->cursor_height)) {
+ weston_log("failed to set cursor: %m\n");
+- b->cursors_are_broken = 1;
++ goto err;
+ }
+ }
+
+- weston_view_to_global_float(ev, 0, 0, &x, &y);
++ pixman_region32_fini(&plane->base.damage);
++ pixman_region32_init(&plane->base.damage);
+
+- /* From global to output space, output transform is guaranteed to be
+- * NORMAL by drm_output_prepare_cursor_view().
+- */
+- x = (x - output->base.x) * output->base.current_scale;
+- y = (y - output->base.y) * output->base.current_scale;
++ if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
++ state->dest_x, state->dest_y)) {
++ weston_log("failed to move cursor: %m\n");
++ goto err;
++ }
+
+- if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
+- if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
+- weston_log("failed to move cursor: %m\n");
+- b->cursors_are_broken = 1;
+- }
++ return;
+
+- output->cursor_plane.x = x;
+- output->cursor_plane.y = y;
+- }
++err:
++ b->cursors_are_broken = 1;
++ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+ }
+
+ static void
+-drm_assign_planes(struct weston_output *output_base)
++drm_assign_planes(struct weston_output *output_base, void *repaint_data)
+ {
+ struct drm_backend *b = to_drm_backend(output_base->compositor);
++ struct drm_pending_state *pending_state = repaint_data;
+ struct drm_output *output = to_drm_output(output_base);
+- struct weston_view *ev, *next;
+- pixman_region32_t overlap, surface_overlap;
++ struct drm_output_state *state;
++ struct drm_plane_state *plane_state;
++ struct weston_view *ev;
++ pixman_region32_t surface_overlap, renderer_region;
+ struct weston_plane *primary, *next_plane;
++ bool picked_scanout = false;
++
++ assert(!output->state_last);
++ state = drm_output_state_duplicate(output->state_cur,
++ pending_state,
++ DRM_OUTPUT_STATE_CLEAR_PLANES);
+
+ /*
+ * Find a surface for each sprite in the output using some heuristics:
+@@ -1326,10 +3067,10 @@ drm_assign_planes(struct weston_output *output_base)
+ * the client buffer can be used directly for the sprite surface
+ * as we do for flipping full screen surfaces.
+ */
+- pixman_region32_init(&overlap);
++ pixman_region32_init(&renderer_region);
+ primary = &output_base->compositor->primary_plane;
+
+- wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
++ wl_list_for_each(ev, &output_base->compositor->view_list, link) {
+ struct weston_surface *es = ev->surface;
+
+ /* Test whether this buffer can ever go into a plane:
+@@ -1350,29 +3091,40 @@ drm_assign_planes(struct weston_output *output_base)
+ es->keep_buffer = false;
+
+ pixman_region32_init(&surface_overlap);
+- pixman_region32_intersect(&surface_overlap, &overlap,
++ pixman_region32_intersect(&surface_overlap, &renderer_region,
+ &ev->transform.boundingbox);
+
+ next_plane = NULL;
+- if (pixman_region32_not_empty(&surface_overlap))
++ if (pixman_region32_not_empty(&surface_overlap) || picked_scanout)
+ next_plane = primary;
+ if (next_plane == NULL)
+- next_plane = drm_output_prepare_cursor_view(output, ev);
+- if (next_plane == NULL)
+- next_plane = drm_output_prepare_scanout_view(output, ev);
++ next_plane = drm_output_prepare_cursor_view(state, ev);
++
++ /* If a higher-stacked view already got assigned to scanout, it's incorrect to
++ * assign a subsequent (lower-stacked) view to scanout.
++ */
++ if (next_plane == NULL) {
++ next_plane = drm_output_prepare_scanout_view(state, ev);
++ if (next_plane)
++ picked_scanout = true;
++ }
++
+ if (next_plane == NULL)
+- next_plane = drm_output_prepare_overlay_view(output, ev);
++ next_plane = drm_output_prepare_overlay_view(state, ev);
++
+ if (next_plane == NULL)
+ next_plane = primary;
+
+ weston_view_move_to_plane(ev, next_plane);
+
+ if (next_plane == primary)
+- pixman_region32_union(&overlap, &overlap,
++ pixman_region32_union(&renderer_region,
++ &renderer_region,
+ &ev->transform.boundingbox);
+
+ if (next_plane == primary ||
+- next_plane == &output->cursor_plane) {
++ (output->cursor_plane &&
++ next_plane == &output->cursor_plane->base)) {
+ /* cursor plane involves a copy */
+ ev->psf_flags = 0;
+ } else {
+@@ -1384,7 +3136,20 @@ drm_assign_planes(struct weston_output *output_base)
+
+ pixman_region32_fini(&surface_overlap);
+ }
+- pixman_region32_fini(&overlap);
++ pixman_region32_fini(&renderer_region);
++
++ /* We rely on output->cursor_view being both an accurate reflection of
++ * the cursor plane's state, but also being maintained across repaints
++ * to avoid unnecessary damage uploads, per the comment in
++ * drm_output_prepare_cursor_view. In the event that we go from having
++ * a cursor view to not having a cursor view, we need to clear it. */
++ if (output->cursor_view) {
++ plane_state =
++ drm_output_state_get_existing_plane(state,
++ output->cursor_plane);
++ if (!plane_state || !plane_state->fb)
++ output->cursor_view = NULL;
++ }
+ }
+
+ /**
+@@ -1407,7 +3172,7 @@ choose_mode (struct drm_output *output, struct weston_mode *target_mode)
+ output->base.current_mode->height == target_mode->height &&
+ (output->base.current_mode->refresh == target_mode->refresh ||
+ target_mode->refresh == 0))
+- return (struct drm_mode *)output->base.current_mode;
++ return to_drm_mode(output->base.current_mode);
+
+ wl_list_for_each(mode, &output->base.mode_list, base.link) {
+ if (mode->mode_info.hdisplay == target_mode->width &&
+@@ -1435,26 +3200,13 @@ drm_output_fini_pixman(struct drm_output *output);
+ static int
+ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
+ {
+- struct drm_output *output;
+- struct drm_mode *drm_mode;
+- struct drm_backend *b;
+-
+- if (output_base == NULL) {
+- weston_log("output is NULL.\n");
+- return -1;
+- }
+-
+- if (mode == NULL) {
+- weston_log("mode is NULL.\n");
+- return -1;
+- }
+-
+- b = to_drm_backend(output_base->compositor);
+- output = to_drm_output(output_base);
+- drm_mode = choose_mode (output, mode);
++ struct drm_output *output = to_drm_output(output_base);
++ struct drm_backend *b = to_drm_backend(output_base->compositor);
++ struct drm_mode *drm_mode = choose_mode(output, mode);
+
+ if (!drm_mode) {
+- weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
++ weston_log("%s: invalid resolution %dx%d\n",
++ output_base->name, mode->width, mode->height);
+ return -1;
+ }
+
+@@ -1467,10 +3219,13 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
+ output->base.current_mode->flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+- /* reset rendering stuff. */
+- drm_output_release_fb(output, output->current);
+- drm_output_release_fb(output, output->next);
+- output->current = output->next = NULL;
++ /* XXX: This drops our current buffer too early, before we've started
++ * displaying it. Ideally this should be much more atomic and
++ * integrated with a full repaint cycle, rather than doing a
++ * sledgehammer modeswitch first, and only later showing new
++ * content.
++ */
++ b->state_invalid = true;
+
+ if (b->use_pixman) {
+ drm_output_fini_pixman(output);
+@@ -1494,11 +3249,21 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
+ static int
+ on_drm_input(int fd, uint32_t mask, void *data)
+ {
++#ifdef HAVE_DRM_ATOMIC
++ struct drm_backend *b = data;
++#endif
+ drmEventContext evctx;
+
+ memset(&evctx, 0, sizeof evctx);
+- evctx.version = DRM_EVENT_CONTEXT_VERSION;
+- evctx.page_flip_handler = page_flip_handler;
++#ifndef HAVE_DRM_ATOMIC
++ evctx.version = 2;
++#else
++ evctx.version = 3;
++ if (b->atomic_modeset)
++ evctx.page_flip_handler2 = atomic_flip_handler;
++ else
++#endif
++ evctx.page_flip_handler = page_flip_handler;
+ evctx.vblank_handler = vblank_handler;
+ drmHandleEvent(fd, &evctx);
+
+@@ -1506,36 +3271,15 @@ on_drm_input(int fd, uint32_t mask, void *data)
+ }
+
+ static int
+-init_drm(struct drm_backend *b, struct udev_device *device)
++init_kms_caps(struct drm_backend *b)
+ {
+- const char *filename, *sysnum;
+ uint64_t cap;
+- int fd, ret;
++ int ret;
+ clockid_t clk_id;
+
+- sysnum = udev_device_get_sysnum(device);
+- if (sysnum)
+- b->drm.id = atoi(sysnum);
+- if (!sysnum || b->drm.id < 0) {
+- weston_log("cannot get device sysnum\n");
+- return -1;
+- }
+-
+- filename = udev_device_get_devnode(device);
+- fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
+- if (fd < 0) {
+- /* Probably permissions error */
+- weston_log("couldn't open %s, skipping\n",
+- udev_device_get_devnode(device));
+- return -1;
+- }
+-
+- weston_log("using %s\n", filename);
+-
+- b->drm.fd = fd;
+- b->drm.filename = strdup(filename);
++ weston_log("using %s\n", b->drm.filename);
+
+- ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
++ ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
+ if (ret == 0 && cap == 1)
+ clk_id = CLOCK_MONOTONIC;
+ else
+@@ -1547,18 +3291,40 @@ init_drm(struct drm_backend *b, struct udev_device *device)
+ return -1;
+ }
+
+- ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
++ ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
+ if (ret == 0)
+ b->cursor_width = cap;
+ else
+ b->cursor_width = 64;
+
+- ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
++ ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
+ if (ret == 0)
+ b->cursor_height = cap;
+ else
+ b->cursor_height = 64;
+
++ if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
++ ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
++ b->universal_planes = (ret == 0);
++ }
++ weston_log("DRM: %s universal planes\n",
++ b->universal_planes ? "supports" : "does not support");
++
++#ifdef HAVE_DRM_ATOMIC
++ if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
++ #if 0
++ ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
++ if (ret != 0)
++ cap = 0;
++ #endif
++ cap = 1 ;
++ ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
++ b->atomic_modeset = ((ret == 0) && (cap == 1));
++ }
++#endif
++ weston_log("DRM: %s atomic modesetting\n",
++ b->atomic_modeset ? "supports" : "does not support");
++
+ return 0;
+ }
+
+@@ -1642,7 +3408,6 @@ init_egl(struct drm_backend *b)
+
+ if (drm_backend_create_gl_renderer(b) < 0) {
+ gbm_device_destroy(b->gbm);
+- b->gbm = NULL;
+ return -1;
+ }
+
+@@ -1656,6 +3421,293 @@ init_pixman(struct drm_backend *b)
+ }
+
+ /**
++ * Create a drm_plane for a hardware plane
++ *
++ * Creates one drm_plane structure for a hardware plane, and initialises its
++ * properties and formats.
++ *
++ * In the absence of universal plane support, where KMS does not explicitly
++ * expose the primary and cursor planes to userspace, this may also create
++ * an 'internal' plane for internal management.
++ *
++ * This function does not add the plane to the list of usable planes in Weston
++ * itself; the caller is responsible for this.
++ *
++ * Call drm_plane_destroy to clean up the plane.
++ *
++ * @sa drm_output_find_special_plane
++ * @param b DRM compositor backend
++ * @param kplane DRM plane to create, or NULL if creating internal plane
++ * @param output Output to create internal plane for, or NULL
++ * @param type Type to use when creating internal plane, or invalid
++ * @param format Format to use for internal planes, or 0
++ */
++static struct drm_plane *
++drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
++ struct drm_output *output, enum wdrm_plane_type type,
++ uint32_t format)
++{
++ struct drm_plane *plane;
++ drmModeObjectProperties *props;
++ int num_formats = (kplane) ? kplane->count_formats : 1;
++
++ plane = zalloc(sizeof(*plane) +
++ (sizeof(uint32_t) * num_formats));
++ if (!plane) {
++ weston_log("%s: out of memory\n", __func__);
++ return NULL;
++ }
++
++ plane->backend = b;
++ plane->state_cur = drm_plane_state_alloc(NULL, plane);
++ plane->state_cur->complete = true;
++
++ if (kplane) {
++ plane->possible_crtcs = kplane->possible_crtcs;
++ plane->plane_id = kplane->plane_id;
++ plane->count_formats = kplane->count_formats;
++ memcpy(plane->formats, kplane->formats,
++ kplane->count_formats * sizeof(kplane->formats[0]));
++
++ props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
++ DRM_MODE_OBJECT_PLANE);
++ if (!props) {
++ weston_log("couldn't get plane properties\n");
++ goto err;
++ }
++ drm_property_info_populate(b, plane_props, plane->props,
++ WDRM_PLANE__COUNT, props);
++ plane->type =
++ drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
++ props,
++ WDRM_PLANE_TYPE__COUNT);
++ drmModeFreeObjectProperties(props);
++ }
++ else {
++ plane->possible_crtcs = (1 << output->pipe);
++ plane->plane_id = 0;
++ plane->count_formats = 1;
++ plane->formats[0] = format;
++ plane->type = type;
++ }
++
++ if (plane->type == WDRM_PLANE_TYPE__COUNT)
++ goto err_props;
++
++ /* With universal planes, everything is a DRM plane; without
++ * universal planes, the only DRM planes are overlay planes.
++ * Everything else is a fake plane. */
++ if (b->universal_planes) {
++ assert(kplane);
++ } else {
++ if (kplane)
++ assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
++ else
++ assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
++ output);
++ }
++
++ weston_plane_init(&plane->base, b->compositor, 0, 0);
++ wl_list_insert(&b->plane_list, &plane->link);
++
++ return plane;
++
++err_props:
++ drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
++err:
++ drm_plane_state_free(plane->state_cur, true);
++ free(plane);
++ return NULL;
++}
++
++/**
++ * Find, or create, a special-purpose plane
++ *
++ * Primary and cursor planes are a special case, in that before universal
++ * planes, they are driven by non-plane API calls. Without universal plane
++ * support, the only way to configure a primary plane is via drmModeSetCrtc,
++ * and the only way to configure a cursor plane is drmModeSetCursor2.
++ *
++ * Although they may actually be regular planes in the hardware, without
++ * universal plane support, these planes are not actually exposed to
++ * userspace in the regular plane list.
++ *
++ * However, for ease of internal tracking, we want to manage all planes
++ * through the same drm_plane structures. Therefore, when we are running
++ * without universal plane support, we create fake drm_plane structures
++ * to track these planes.
++ *
++ * @param b DRM backend
++ * @param output Output to use for plane
++ * @param type Type of plane
++ */
++static struct drm_plane *
++drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
++ enum wdrm_plane_type type)
++{
++ struct drm_plane *plane;
++
++ if (!b->universal_planes) {
++ uint32_t format;
++
++ switch (type) {
++ case WDRM_PLANE_TYPE_CURSOR:
++ format = GBM_FORMAT_ARGB8888;
++ break;
++ case WDRM_PLANE_TYPE_PRIMARY:
++ /* We don't know what formats the primary plane supports
++ * before universal planes, so we just assume that the
++ * GBM format works; however, this isn't set until after
++ * the output is created. */
++ format = 0;
++ break;
++ default:
++ assert(!"invalid type in drm_output_find_special_plane");
++ break;
++ }
++
++ return drm_plane_create(b, NULL, output, type, format);
++ }
++
++ wl_list_for_each(plane, &b->plane_list, link) {
++ struct drm_output *tmp;
++ bool found_elsewhere = false;
++
++ if (plane->type != type)
++ continue;
++ if (!drm_plane_is_available(plane, output))
++ continue;
++
++ /* On some platforms, primary/cursor planes can roam
++ * between different CRTCs, so make sure we don't claim the
++ * same plane for two outputs. */
++ wl_list_for_each(tmp, &b->compositor->pending_output_list,
++ base.link) {
++ if (tmp->cursor_plane == plane ||
++ tmp->scanout_plane == plane) {
++ found_elsewhere = true;
++ break;
++ }
++ }
++ wl_list_for_each(tmp, &b->compositor->output_list,
++ base.link) {
++ if (tmp->cursor_plane == plane ||
++ tmp->scanout_plane == plane) {
++ found_elsewhere = true;
++ break;
++ }
++ }
++
++ if (found_elsewhere)
++ continue;
++
++ plane->possible_crtcs = (1 << output->pipe);
++ return plane;
++ }
++
++ return NULL;
++}
++
++/**
++ * Destroy one DRM plane
++ *
++ * Destroy a DRM plane, removing it from screen and releasing its retained
++ * buffers in the process. The counterpart to drm_plane_create.
++ *
++ * @param plane Plane to deallocate (will be freed)
++ */
++static void
++drm_plane_destroy(struct drm_plane *plane)
++{
++ if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
++ drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
++ drm_plane_state_free(plane->state_cur, true);
++ drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
++ weston_plane_release(&plane->base);
++ wl_list_remove(&plane->link);
++ free(plane);
++}
++
++/**
++ * Initialise sprites (overlay planes)
++ *
++ * Walk the list of provided DRM planes, and add overlay planes.
++ *
++ * Call destroy_sprites to free these planes.
++ *
++ * @param b DRM compositor backend
++ */
++static void
++create_sprites(struct drm_backend *b)
++{
++ drmModePlaneRes *kplane_res;
++ drmModePlane *kplane;
++ struct drm_plane *drm_plane;
++ uint32_t i;
++ kplane_res = drmModeGetPlaneResources(b->drm.fd);
++ if (!kplane_res) {
++ weston_log("failed to get plane resources: %s\n",
++ strerror(errno));
++ return;
++ }
++
++ for (i = 0; i < kplane_res->count_planes; i++) {
++ kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
++ if (!kplane)
++ continue;
++
++ drm_plane = drm_plane_create(b, kplane, NULL,
++ WDRM_PLANE_TYPE__COUNT, 0);
++ drmModeFreePlane(kplane);
++ if (!drm_plane)
++ continue;
++
++ if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
++ weston_compositor_stack_plane(b->compositor,
++ &drm_plane->base,
++ &b->compositor->primary_plane);
++ }
++
++ drmModeFreePlaneResources(kplane_res);
++}
++
++/**
++ * Clean up sprites (overlay planes)
++ *
++ * The counterpart to create_sprites.
++ *
++ * @param b DRM compositor backend
++ */
++static void
++destroy_sprites(struct drm_backend *b)
++{
++ struct drm_plane *plane, *next;
++
++ wl_list_for_each_safe(plane, next, &b->plane_list, link)
++ drm_plane_destroy(plane);
++}
++
++static uint32_t
++drm_refresh_rate_mHz(const drmModeModeInfo *info)
++{
++ uint64_t refresh;
++
++ /* Calculate higher precision (mHz) refresh rate */
++ refresh = (info->clock * 1000000LL / info->htotal +
++ info->vtotal / 2) / info->vtotal;
++
++ if (info->flags & DRM_MODE_FLAG_INTERLACE)
++ refresh *= 2;
++ if (info->flags & DRM_MODE_FLAG_DBLSCAN)
++ refresh /= 2;
++ if (info->vscan > 1)
++ refresh /= info->vscan;
++
++ return refresh;
++}
++
++/**
+ * Add a mode to output's mode list
+ *
+ * Copy the supplied DRM mode into a Weston mode structure, and add it to the
+@@ -1669,7 +3721,6 @@ static struct drm_mode *
+ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
+ {
+ struct drm_mode *mode;
+- uint64_t refresh;
+
+ mode = malloc(sizeof *mode);
+ if (mode == NULL)
+@@ -1679,19 +3730,9 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
+ mode->base.width = info->hdisplay;
+ mode->base.height = info->vdisplay;
+
+- /* Calculate higher precision (mHz) refresh rate */
+- refresh = (info->clock * 1000000LL / info->htotal +
+- info->vtotal / 2) / info->vtotal;
+-
+- if (info->flags & DRM_MODE_FLAG_INTERLACE)
+- refresh *= 2;
+- if (info->flags & DRM_MODE_FLAG_DBLSCAN)
+- refresh /= 2;
+- if (info->vscan > 1)
+- refresh /= info->vscan;
+-
+- mode->base.refresh = refresh;
++ mode->base.refresh = drm_refresh_rate_mHz(info);
+ mode->mode_info = *info;
++ mode->blob_id = 0;
+
+ if (info->type & DRM_MODE_TYPE_PREFERRED)
+ mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
+@@ -1701,6 +3742,32 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
+ return mode;
+ }
+
++/**
++ * Destroys a mode, and removes it from the list.
++ */
++static void
++drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
++{
++ if (mode->blob_id)
++ drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
++ wl_list_remove(&mode->base.link);
++ free(mode);
++}
++
++/** Destroy a list of drm_modes
++ *
++ * @param backend The backend for releasing mode property blobs.
++ * @param mode_list The list linked by drm_mode::base.link.
++ */
++static void
++drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
++{
++ struct drm_mode *mode, *next;
++
++ wl_list_for_each_safe(mode, next, mode_list, base.link)
++ drm_output_destroy_mode(backend, mode);
++}
++
+ static int
+ drm_subpixel_to_wayland(int drm_value)
+ {
+@@ -1757,46 +3824,72 @@ drm_set_backlight(struct weston_output *output_base, uint32_t value)
+ backlight_set_brightness(output->backlight, new_brightness);
+ }
+
+-static drmModePropertyPtr
+-drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
+-{
+- drmModePropertyPtr props;
+- int i;
+-
+- for (i = 0; i < connector->count_props; i++) {
+- props = drmModeGetProperty(fd, connector->props[i]);
+- if (!props)
+- continue;
+-
+- if (!strcmp(props->name, name))
+- return props;
+-
+- drmModeFreeProperty(props);
+- }
+-
+- return NULL;
+-}
+-
++/**
++ * Power output on or off
++ *
++ * The DPMS/power level of an output is used to switch it on or off. This
++ * is DRM's hook for doing so, which can called either as part of repaint,
++ * or independently of the repaint loop.
++ *
++ * If we are called as part of repaint, we simply set the relevant bit in
++ * state and return.
++ */
+ static void
+ drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
+ {
+ struct drm_output *output = to_drm_output(output_base);
+- struct weston_compositor *ec = output_base->compositor;
+- struct drm_backend *b = to_drm_backend(ec);
++ struct drm_backend *b = to_drm_backend(output_base->compositor);
++ struct drm_pending_state *pending_state = b->repaint_data;
++ struct drm_output_state *state;
+ int ret;
+
+- if (!output->dpms_prop)
++ if (output->state_cur->dpms == level)
+ return;
+
+- ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
+- output->dpms_prop->prop_id, level);
+- if (ret) {
+- weston_log("DRM: DPMS: failed property set for %s\n",
+- output->base.name);
++ /* If we're being called during the repaint loop, then this is
++ * simple: discard any previously-generated state, and create a new
++ * state where we disable everything. When we come to flush, this
++ * will be applied.
++ *
++ * However, we need to be careful: we can be called whilst another
++ * output is in its repaint cycle (pending_state exists), but our
++ * output still has an incomplete state application outstanding.
++ * In that case, we need to wait until that completes. */
++ if (pending_state && !output->state_last) {
++ /* The repaint loop already sets DPMS on; we don't need to
++ * explicitly set it on here, as it will already happen
++ * whilst applying the repaint state. */
++ if (level == WESTON_DPMS_ON)
++ return;
++
++ state = drm_pending_state_get_output(pending_state, output);
++ if (state)
++ drm_output_state_free(state);
++ state = drm_output_get_disable_state(pending_state, output);
+ return;
+ }
+
+- output->dpms = level;
++ /* As we throw everything away when disabling, just send us back through
++ * a repaint cycle. */
++ if (level == WESTON_DPMS_ON) {
++ if (output->dpms_off_pending)
++ output->dpms_off_pending = 0;
++ weston_output_schedule_repaint(output_base);
++ return;
++ }
++
++ /* If we've already got a request in the pipeline, then we need to
++ * park our DPMS request until that request has quiesced. */
++ if (output->state_last) {
++ output->dpms_off_pending = 1;
++ return;
++ }
++
++ pending_state = drm_pending_state_alloc(b);
++ drm_output_get_disable_state(pending_state, output);
++ ret = drm_pending_state_apply_sync(pending_state);
++ if (ret != 0)
++ weston_log("drm_set_dpms: couldn't disable output?\n");
+ }
+
+ static const char * const connector_type_names[] = {
+@@ -1821,11 +3914,20 @@ static const char * const connector_type_names[] = {
+ #endif
+ };
+
++/** Create a name given a DRM connector
++ *
++ * \param con The DRM connector whose type and id form the name.
++ * \return A newly allocate string, or NULL on error. Must be free()'d
++ * after use.
++ *
++ * The name does not identify the DRM display device.
++ */
+ static char *
+ make_connector_name(const drmModeConnector *con)
+ {
+- char name[32];
++ char *name;
+ const char *type_name = NULL;
++ int ret;
+
+ if (con->connector_type < ARRAY_LENGTH(connector_type_names))
+ type_name = connector_type_names[con->connector_type];
+@@ -1833,9 +3935,11 @@ make_connector_name(const drmModeConnector *con)
+ if (!type_name)
+ type_name = "UNNAMED";
+
+- snprintf(name, sizeof name, "%s-%d", type_name, con->connector_type_id);
++ ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
++ if (ret < 0)
++ return NULL;
+
+- return strdup(name);
++ return name;
+ }
+
+ static int
+@@ -1843,16 +3947,20 @@ find_crtc_for_connector(struct drm_backend *b,
+ drmModeRes *resources, drmModeConnector *connector)
+ {
+ drmModeEncoder *encoder;
+- uint32_t possible_crtcs;
+ int i, j;
++ int ret = -1;
+
+ for (j = 0; j < connector->count_encoders; j++) {
++ uint32_t possible_crtcs, encoder_id, crtc_id;
++
+ encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
+ if (encoder == NULL) {
+ weston_log("Failed to get encoder.\n");
+- return -1;
++ continue;
+ }
++ encoder_id = encoder->encoder_id;
+ possible_crtcs = encoder->possible_crtcs;
++ crtc_id = encoder->crtc_id;
+ drmModeFreeEncoder(encoder);
+
+ for (i = 0; i < resources->count_crtcs; i++) {
+@@ -1862,10 +3970,66 @@ find_crtc_for_connector(struct drm_backend *b,
+ if (drm_output_find_by_crtc(b, resources->crtcs[i]))
+ continue;
+
+- return i;
++ /* Try to preserve the existing
++ * CRTC -> encoder -> connector routing; it makes
++ * initialisation faster, and also since we have a
++ * very dumb picking algorithm, may preserve a better
++ * choice. */
++ if (!connector->encoder_id ||
++ (encoder_id == connector->encoder_id &&
++ crtc_id == resources->crtcs[i]))
++ return i;
++
++ ret = i;
++ }
++ }
++
++ return ret;
++}
++
++static void drm_output_fini_cursor_egl(struct drm_output *output)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
++ drm_fb_unref(output->gbm_cursor_fb[i]);
++ output->gbm_cursor_fb[i] = NULL;
++ }
++}
++
++static int
++drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
++{
++ unsigned int i;
++
++ /* No point creating cursors if we don't have a plane for them. */
++ if (!output->cursor_plane)
++ return 0;
++
++ for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
++ struct gbm_bo *bo;
++
++ bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
++ GBM_FORMAT_ARGB8888,
++ GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
++ if (!bo)
++ goto err;
++
++ output->gbm_cursor_fb[i] =
++ drm_fb_get_from_bo(bo, b, GBM_FORMAT_ARGB8888,
++ BUFFER_CURSOR);
++ if (!output->gbm_cursor_fb[i]) {
++ gbm_bo_destroy(bo);
++ goto err;
+ }
+ }
+
++ return 0;
++
++err:
++ weston_log("cursor buffers unavailable, using gl cursors\n");
++ b->cursors_are_broken = 1;
++ drm_output_fini_cursor_egl(output);
+ return -1;
+ }
+
+@@ -1877,7 +4041,7 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
+ output->gbm_format,
+ fallback_format_for(output->gbm_format),
+ };
+- int i, flags, n_formats = 1;
++ int n_formats = 1;
+
+ output->gbm_surface = gbm_surface_create(b->gbm,
+ output->base.current_mode->width,
+@@ -1903,21 +4067,7 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
+ return -1;
+ }
+
+- flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
+-
+- for (i = 0; i < 2; i++) {
+- if (output->gbm_cursor_bo[i])
+- continue;
+-
+- output->gbm_cursor_bo[i] =
+- gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
+- GBM_FORMAT_ARGB8888, flags);
+- }
+-
+- if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == NULL) {
+- weston_log("cursor buffers unavailable, using gl cursors\n");
+- b->cursors_are_broken = 1;
+- }
++ drm_output_init_cursor_egl(output, b);
+
+ return 0;
+ }
+@@ -1925,8 +4075,22 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
+ static void
+ drm_output_fini_egl(struct drm_output *output)
+ {
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
++
++ /* Destroying the GBM surface will destroy all our GBM buffers,
++ * regardless of refcount. Ensure we destroy them here. */
++ if (!b->shutting_down &&
++ output->scanout_plane->state_cur->fb &&
++ output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
++ drm_plane_state_free(output->scanout_plane->state_cur, true);
++ output->scanout_plane->state_cur =
++ drm_plane_state_alloc(NULL, output->scanout_plane);
++ output->scanout_plane->state_cur->complete = true;
++ }
++
+ gl_renderer->output_destroy(&output->base);
+ gbm_surface_destroy(output->gbm_surface);
++ drm_output_fini_cursor_egl(output);
+ }
+
+ static int
+@@ -1975,7 +4139,7 @@ drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
+ err:
+ for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+ if (output->dumb[i])
+- drm_fb_destroy_dumb(output->dumb[i]);
++ drm_fb_unref(output->dumb[i]);
+ if (output->image[i])
+ pixman_image_unref(output->image[i]);
+
+@@ -1989,14 +4153,26 @@ err:
+ static void
+ drm_output_fini_pixman(struct drm_output *output)
+ {
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
+ unsigned int i;
+
++ /* Destroying the Pixman surface will destroy all our buffers,
++ * regardless of refcount. Ensure we destroy them here. */
++ if (!b->shutting_down &&
++ output->scanout_plane->state_cur->fb &&
++ output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
++ drm_plane_state_free(output->scanout_plane->state_cur, true);
++ output->scanout_plane->state_cur =
++ drm_plane_state_alloc(NULL, output->scanout_plane);
++ output->scanout_plane->state_cur->complete = true;
++ }
++
+ pixman_renderer_output_destroy(&output->base);
+ pixman_region32_fini(&output->previous_damage);
+
+ for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+- drm_fb_destroy_dumb(output->dumb[i]);
+ pixman_image_unref(output->image[i]);
++ drm_fb_unref(output->dumb[i]);
+ output->dumb[i] = NULL;
+ output->image[i] = NULL;
+ }
+@@ -2100,27 +4276,38 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
+ return 0;
+ }
+
++/** Parse monitor make, model and serial from EDID
++ *
++ * \param b The backend instance.
++ * \param output The output whose \c drm_edid to fill in.
++ * \param props The DRM connector properties to get the EDID from.
++ * \param make[out] The monitor make (PNP ID).
++ * \param model[out] The monitor model (name).
++ * \param serial_number[out] The monitor serial number.
++ *
++ * Each of \c *make, \c *model and \c *serial_number are set only if the
++ * information is found in the EDID. The pointers they are set to must not
++ * be free()'d explicitly, instead they get implicitly freed when the
++ * \c drm_output is destroyed.
++ */
+ static void
+-find_and_parse_output_edid(struct drm_backend *b,
+- struct drm_output *output,
+- drmModeConnector *connector)
++find_and_parse_output_edid(struct drm_backend *b, struct drm_output *output,
++ drmModeObjectPropertiesPtr props,
++ const char **make,
++ const char **model,
++ const char **serial_number)
+ {
+ drmModePropertyBlobPtr edid_blob = NULL;
+- drmModePropertyPtr property;
+- int i;
++ uint32_t blob_id;
+ int rc;
+
+- for (i = 0; i < connector->count_props && !edid_blob; i++) {
+- property = drmModeGetProperty(b->drm.fd, connector->props[i]);
+- if (!property)
+- continue;
+- if ((property->flags & DRM_MODE_PROP_BLOB) &&
+- !strcmp(property->name, "EDID")) {
+- edid_blob = drmModeGetPropertyBlob(b->drm.fd,
+- connector->prop_values[i]);
+- }
+- drmModeFreeProperty(property);
+- }
++ blob_id =
++ drm_property_get_value(&output->props_conn[WDRM_CONNECTOR_EDID],
++ props, 0);
++ if (!blob_id)
++ return;
++
++ edid_blob = drmModeGetPropertyBlob(b->drm.fd, blob_id);
+ if (!edid_blob)
+ return;
+
+@@ -2133,17 +4320,15 @@ find_and_parse_output_edid(struct drm_backend *b,
+ output->edid.monitor_name,
+ output->edid.serial_number);
+ if (output->edid.pnp_id[0] != '\0')
+- output->base.make = output->edid.pnp_id;
++ *make = output->edid.pnp_id;
+ if (output->edid.monitor_name[0] != '\0')
+- output->base.model = output->edid.monitor_name;
++ *model = output->edid.monitor_name;
+ if (output->edid.serial_number[0] != '\0')
+- output->base.serial_number = output->edid.serial_number;
++ *serial_number = output->edid.serial_number;
+ }
+ drmModeFreePropertyBlob(edid_blob);
+ }
+
+-
+-
+ static int
+ parse_modeline(const char *s, drmModeModeInfo *mode)
+ {
+@@ -2151,6 +4336,8 @@ parse_modeline(const char *s, drmModeModeInfo *mode)
+ char vsync[16];
+ float fclock;
+
++ memset(mode, 0, sizeof *mode);
++
+ mode->type = DRM_MODE_TYPE_USERDEF;
+ mode->hskew = 0;
+ mode->vscan = 0;
+@@ -2355,29 +4542,15 @@ drm_output_set_mode(struct weston_output *base,
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+
+- struct drm_mode *drm_mode, *next, *current;
+- drmModeModeInfo crtc_mode;
+- int i;
+-
+- output->base.make = "unknown";
+- output->base.model = "unknown";
+- output->base.serial_number = "unknown";
+- wl_list_init(&output->base.mode_list);
+-
+- output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
++ struct drm_mode *current;
++ drmModeModeInfo crtc_mode;
+
+ if (connector_get_current_mode(output->connector, b->drm.fd, &crtc_mode) < 0)
+- goto err_free;
+-
+- for (i = 0; i < output->connector->count_modes; i++) {
+- drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
+- if (!drm_mode)
+- goto err_free;
+- }
++ return -1;
+
+ current = drm_output_choose_initial_mode(b, output, mode, modeline, &crtc_mode);
+ if (!current)
+- goto err_free;
++ return -1;
+
+ output->base.current_mode = ¤t->base;
+ output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
+@@ -2386,22 +4559,7 @@ drm_output_set_mode(struct weston_output *base,
+ output->base.native_mode = output->base.current_mode;
+ output->base.native_scale = output->base.current_scale;
+
+- output->base.mm_width = output->connector->mmWidth;
+- output->base.mm_height = output->connector->mmHeight;
+-
+ return 0;
+-
+-err_free:
+- drmModeFreeCrtc(output->original_crtc);
+- output->original_crtc = NULL;
+-
+- wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
+- base.link) {
+- wl_list_remove(&drm_mode->base.link);
+- free(drm_mode);
+- }
+-
+- return -1;
+ }
+
+ static void
+@@ -2413,6 +4571,12 @@ drm_output_set_gbm_format(struct weston_output *base,
+
+ if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
+ output->gbm_format = b->gbm_format;
++
++ /* Without universal planes, we can't discover which formats are
++ * supported by the primary plane; we just hope that the GBM format
++ * works. */
++ if (!b->universal_planes)
++ output->scanout_plane->formats[0] = output->gbm_format;
+ }
+
+ static void
+@@ -2427,22 +4591,145 @@ drm_output_set_seat(struct weston_output *base,
+ }
+
+ static int
++drm_output_init_gamma_size(struct drm_output *output)
++{
++ struct drm_backend *backend = to_drm_backend(output->base.compositor);
++ drmModeCrtc *crtc;
++
++ assert(output->base.compositor);
++ assert(output->crtc_id != 0);
++ crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
++ if (!crtc)
++ return -1;
++
++ output->base.gamma_size = crtc->gamma_size;
++
++ drmModeFreeCrtc(crtc);
++
++ return 0;
++}
++
++/** Allocate a CRTC for the output
++ *
++ * @param output The output with no allocated CRTC.
++ * @param resources DRM KMS resources.
++ * @param connector The DRM KMS connector data.
++ * @return 0 on success, -1 on failure.
++ *
++ * Finds a free CRTC that can drive the given connector, reserves the CRTC
++ * for the output, and loads the CRTC properties.
++ *
++ * Populates the cursor and scanout planes.
++ *
++ * On failure, the output remains without a CRTC.
++ */
++static int
++drm_output_init_crtc(struct drm_output *output,
++ drmModeRes *resources, drmModeConnector *connector)
++{
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
++ drmModeObjectPropertiesPtr props;
++ int i;
++
++ assert(output->crtc_id == 0);
++
++ i = find_crtc_for_connector(b, resources, connector);
++ if (i < 0) {
++ weston_log("No usable crtc/encoder pair for connector.\n");
++ return -1;
++ }
++
++ output->crtc_id = resources->crtcs[i];
++ output->pipe = i;
++
++ props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
++ DRM_MODE_OBJECT_CRTC);
++ if (!props) {
++ weston_log("failed to get CRTC properties\n");
++ goto err_crtc;
++ }
++ drm_property_info_populate(b, crtc_props, output->props_crtc,
++ WDRM_CRTC__COUNT, props);
++ drmModeFreeObjectProperties(props);
++
++ output->scanout_plane =
++ drm_output_find_special_plane(b, output,
++ WDRM_PLANE_TYPE_PRIMARY);
++ if (!output->scanout_plane) {
++ weston_log("Failed to find primary plane for output %s\n",
++ output->base.name);
++ goto err_crtc;
++ }
++
++ /* Failing to find a cursor plane is not fatal, as we'll fall back
++ * to software cursor. */
++ output->cursor_plane =
++ drm_output_find_special_plane(b, output,
++ WDRM_PLANE_TYPE_CURSOR);
++
++ return 0;
++
++err_crtc:
++ output->crtc_id = 0;
++ output->pipe = 0;
++
++ return -1;
++}
++
++/** Free the CRTC from the output
++ *
++ * @param output The output whose CRTC to deallocate.
++ *
++ * The CRTC reserved for the given output becomes free to use again.
++ */
++static void
++drm_output_fini_crtc(struct drm_output *output)
++{
++ struct drm_backend *b = to_drm_backend(output->base.compositor);
++
++ if (!b->universal_planes && !b->shutting_down) {
++ /* With universal planes, the 'special' planes are allocated at
++ * startup, freed at shutdown, and live on the plane list in
++ * between. We want the planes to continue to exist and be freed
++ * up for other outputs.
++ *
++ * Without universal planes, our special planes are
++ * pseudo-planes allocated at output creation, freed at output
++ * destruction, and not usable by other outputs.
++ *
++ * On the other hand, if the compositor is already shutting down,
++ * the plane has already been destroyed.
++ */
++ if (output->cursor_plane)
++ drm_plane_destroy(output->cursor_plane);
++ if (output->scanout_plane)
++ drm_plane_destroy(output->scanout_plane);
++ }
++
++ drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
++ output->crtc_id = 0;
++ output->cursor_plane = NULL;
++ output->scanout_plane = NULL;
++}
++
++static int
+ drm_output_enable(struct weston_output *base)
+ {
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+ struct weston_mode *m;
+
+- output->dpms_prop = drm_get_prop(b->drm.fd, output->connector, "DPMS");
++ if (b->pageflip_timeout)
++ drm_output_pageflip_timer_create(output);
+
+ if (b->use_pixman) {
+ if (drm_output_init_pixman(output, b) < 0) {
+ weston_log("Failed to init output pixman state\n");
+- goto err_free;
++ goto err;
+ }
+ } else if (drm_output_init_egl(output, b) < 0) {
+ weston_log("Failed to init output gl state\n");
+- goto err_free;
++ goto err;
+ }
+
+ if (output->backlight) {
+@@ -2459,25 +4746,22 @@ drm_output_enable(struct weston_output *base)
+ output->base.assign_planes = drm_assign_planes;
+ output->base.set_dpms = drm_set_dpms;
+ output->base.switch_mode = drm_output_switch_mode;
+-
+- output->base.gamma_size = output->original_crtc->gamma_size;
+ output->base.set_gamma = drm_output_set_gamma;
+
+- output->base.subpixel = drm_subpixel_to_wayland(output->connector->subpixel);
+-
+- find_and_parse_output_edid(b, output, output->connector);
+- if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+- output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+- output->base.connection_internal = 1;
+-
+- weston_plane_init(&output->cursor_plane, b->compositor,
+- INT32_MIN, INT32_MIN);
+- weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
++ if (output->cursor_plane)
++ weston_compositor_stack_plane(b->compositor,
++ &output->cursor_plane->base,
++ NULL);
++ else
++ b->cursors_are_broken = 1;
+
+- weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
+- weston_compositor_stack_plane(b->compositor, &output->fb_plane,
++ weston_compositor_stack_plane(b->compositor,
++ &output->scanout_plane->base,
+ &b->compositor->primary_plane);
+
++ wl_array_remove_uint32(&b->unused_connectors, output->connector_id);
++ wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
++
+ weston_log("Output %s, (connector %d, crtc %d)\n",
+ output->base.name, output->connector_id, output->crtc_id);
+ wl_list_for_each(m, &output->base.mode_list, link)
+@@ -2492,9 +4776,7 @@ drm_output_enable(struct weston_output *base)
+
+ return 0;
+
+-err_free:
+- drmModeFreeProperty(output->dpms_prop);
+-
++err:
+ return -1;
+ }
+
+@@ -2503,19 +4785,36 @@ drm_output_deinit(struct weston_output *base)
+ {
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
++ uint32_t *unused;
+
+ if (b->use_pixman)
+ drm_output_fini_pixman(output);
+ else
+ drm_output_fini_egl(output);
+
+- weston_plane_release(&output->fb_plane);
+- weston_plane_release(&output->cursor_plane);
++ /* Since our planes are no longer in use anywhere, remove their base
++ * weston_plane's link from the plane stacking list, unless we're
++ * shutting down, in which case the plane has already been
++ * destroyed. */
++ if (!b->shutting_down) {
++ wl_list_remove(&output->scanout_plane->base.link);
++ wl_list_init(&output->scanout_plane->base.link);
++
++ if (output->cursor_plane) {
++ wl_list_remove(&output->cursor_plane->base.link);
++ wl_list_init(&output->cursor_plane->base.link);
++ /* Turn off hardware cursor */
++ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
++ }
++ }
+
+- drmModeFreeProperty(output->dpms_prop);
++ unused = wl_array_add(&b->unused_connectors, sizeof(*unused));
++ *unused = output->connector_id;
++ unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
++ *unused = output->crtc_id;
+
+- /* Turn off hardware cursor */
+- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
++ /* Force programming unused connectors and crtcs. */
++ b->state_invalid = true;
+ }
+
+ static void
+@@ -2523,9 +4822,9 @@ drm_output_destroy(struct weston_output *base)
+ {
+ struct drm_output *output = to_drm_output(base);
+ struct drm_backend *b = to_drm_backend(base->compositor);
+- drmModeCrtcPtr origcrtc = output->original_crtc;
+
+- if (output->page_flip_pending) {
++ if (output->page_flip_pending || output->vblank_pending ||
++ output->atomic_complete_pending) {
+ output->destroy_pending = 1;
+ weston_log("destroy output while page flip pending\n");
+ return;
+@@ -2534,21 +4833,24 @@ drm_output_destroy(struct weston_output *base)
+ if (output->base.enabled)
+ drm_output_deinit(&output->base);
+
+- if (origcrtc) {
+- /* Restore original CRTC state */
+- drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
+- origcrtc->x, origcrtc->y,
+- &output->connector_id, 1, &origcrtc->mode);
+- drmModeFreeCrtc(origcrtc);
+- }
++ drm_mode_list_destroy(b, &output->base.mode_list);
++
++ if (output->pageflip_timer)
++ wl_event_source_remove(output->pageflip_timer);
+
+ weston_output_destroy(&output->base);
+
++ drm_output_fini_crtc(output);
++
++ drm_property_info_free(output->props_conn, WDRM_CONNECTOR__COUNT);
+ drmModeFreeConnector(output->connector);
+
+ if (output->backlight)
+ backlight_destroy(output->backlight);
+
++ assert(!output->state_last);
++ drm_output_state_free(output->state_cur);
++
+ free(output);
+ }
+
+@@ -2556,26 +4858,69 @@ static int
+ drm_output_disable(struct weston_output *base)
+ {
+ struct drm_output *output = to_drm_output(base);
+- struct drm_backend *b = to_drm_backend(base->compositor);
+
+- if (output->page_flip_pending) {
++ if (output->page_flip_pending || output->vblank_pending ||
++ output->atomic_complete_pending) {
+ output->disable_pending = 1;
+ return -1;
+ }
+
++ weston_log("Disabling output %s\n", output->base.name);
++
+ if (output->base.enabled)
+ drm_output_deinit(&output->base);
+
+ output->disable_pending = 0;
+
+- weston_log("Disabling output %s\n", output->base.name);
+- drmModeSetCrtc(b->drm.fd, output->crtc_id,
+- 0, 0, 0, 0, 0, NULL);
+-
+ return 0;
+ }
+
+ /**
++ * Update the list of unused connectors and CRTCs
++ *
++ * This keeps the unused_connectors and unused_crtcs arrays up to date.
++ *
++ * @param b Weston backend structure
++ * @param resources DRM resources for this device
++ */
++static void
++drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
++{
++ int i;
++
++ wl_array_release(&b->unused_connectors);
++ wl_array_init(&b->unused_connectors);
++
++ for (i = 0; i < resources->count_connectors; i++) {
++ struct drm_output *output;
++ uint32_t *connector_id;
++
++ output = drm_output_find_by_connector(b, resources->connectors[i]);
++ if (output && output->base.enabled)
++ continue;
++
++ connector_id = wl_array_add(&b->unused_connectors,
++ sizeof(*connector_id));
++ *connector_id = resources->connectors[i];
++ }
++
++ wl_array_release(&b->unused_crtcs);
++ wl_array_init(&b->unused_crtcs);
++
++ for (i = 0; i < resources->count_crtcs; i++) {
++ struct drm_output *output;
++ uint32_t *crtc_id;
++
++ output = drm_output_find_by_crtc(b, resources->crtcs[i]);
++ if (output && output->base.enabled)
++ continue;
++
++ crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
++ *crtc_id = resources->crtcs[i];
++ }
++}
++
++/**
+ * Create a Weston output structure
+ *
+ * Given a DRM connector, create a matching drm_output structure and add it
+@@ -2595,108 +4940,87 @@ create_output_for_connector(struct drm_backend *b,
+ struct udev_device *drm_device)
+ {
+ struct drm_output *output;
++ drmModeObjectPropertiesPtr props;
++ struct drm_mode *drm_mode;
++ char *name;
++ const char *make = "unknown";
++ const char *model = "unknown";
++ const char *serial_number = "unknown";
+ int i;
+
+- i = find_crtc_for_connector(b, resources, connector);
+- if (i < 0) {
+- weston_log("No usable crtc/encoder pair for connector.\n");
+- return -1;
+- }
+-
+ output = zalloc(sizeof *output);
+ if (output == NULL)
+- return -1;
++ goto err_init;
+
+ output->connector = connector;
+- output->crtc_id = resources->crtcs[i];
+- output->pipe = i;
+ output->connector_id = connector->connector_id;
+
+ output->backlight = backlight_init(drm_device,
+ connector->connector_type);
+
++ output->base.name = make_connector_name(connector);
++ weston_output_init(&output->base, b->compositor);
++ wl_list_init(&output->base.mode_list);
++
+ output->base.enable = drm_output_enable;
+ output->base.destroy = drm_output_destroy;
+ output->base.disable = drm_output_disable;
+- output->base.name = make_connector_name(connector);
+
+ output->destroy_pending = 0;
+ output->disable_pending = 0;
+- output->original_crtc = NULL;
+
+- weston_output_init(&output->base, b->compositor);
+- weston_compositor_add_pending_output(&output->base, b->compositor);
++ if (drm_output_init_crtc(output, resources, connector) < 0)
++ goto err_output;
+
+- return 0;
+-}
++ props = drmModeObjectGetProperties(b->drm.fd, connector->connector_id,
++ DRM_MODE_OBJECT_CONNECTOR);
++ if (!props) {
++ weston_log("failed to get connector properties\n");
++ goto err_output;
++ }
++ drm_property_info_populate(b, connector_props, output->props_conn,
++ WDRM_CONNECTOR__COUNT, props);
++ find_and_parse_output_edid(b, output, props,
++ &make, &model, &serial_number);
++ output->base.make = (char *)make;
++ output->base.model = (char *)model;
++ output->base.serial_number = (char *)serial_number;
++ output->base.subpixel = drm_subpixel_to_wayland(output->connector->subpixel);
+
+-static void
+-create_sprites(struct drm_backend *b)
+-{
+- struct drm_sprite *sprite;
+- drmModePlaneRes *plane_res;
+- drmModePlane *plane;
+- uint32_t i;
++ drmModeFreeObjectProperties(props);
+
+- plane_res = drmModeGetPlaneResources(b->drm.fd);
+- if (!plane_res) {
+- weston_log("failed to get plane resources: %s\n",
+- strerror(errno));
+- return;
+- }
++ if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
++ output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
++ output->base.connection_internal = true;
+
+- for (i = 0; i < plane_res->count_planes; i++) {
+- plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
+- if (!plane)
+- continue;
++ if (drm_output_init_gamma_size(output) < 0)
++ goto err_output;
+
+- sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
+- plane->count_formats));
+- if (!sprite) {
+- weston_log("%s: out of memory\n",
+- __func__);
+- drmModeFreePlane(plane);
+- continue;
+- }
++ output->state_cur = drm_output_state_alloc(output, NULL);
+
+- sprite->possible_crtcs = plane->possible_crtcs;
+- sprite->plane_id = plane->plane_id;
+- sprite->current = NULL;
+- sprite->next = NULL;
+- sprite->backend = b;
+- sprite->count_formats = plane->count_formats;
+- memcpy(sprite->formats, plane->formats,
+- plane->count_formats * sizeof(plane->formats[0]));
+- drmModeFreePlane(plane);
+- weston_plane_init(&sprite->plane, b->compositor, 0, 0);
+- weston_compositor_stack_plane(b->compositor, &sprite->plane,
+- &b->compositor->primary_plane);
++ output->base.mm_width = output->connector->mmWidth;
++ output->base.mm_height = output->connector->mmHeight;
+
+- wl_list_insert(&b->sprite_list, &sprite->link);
++ for (i = 0; i < output->connector->count_modes; i++) {
++ drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
++ if (!drm_mode) {
++ weston_log("failed to add mode\n");
++ goto err_output;
++ }
+ }
+
+- drmModeFreePlaneResources(plane_res);
+-}
++ weston_compositor_add_pending_output(&output->base, b->compositor);
+
+-static void
+-destroy_sprites(struct drm_backend *backend)
+-{
+- struct drm_sprite *sprite, *next;
+- struct drm_output *output;
++ return 0;
+
+- output = container_of(backend->compositor->output_list.next,
+- struct drm_output, base.link);
++err_output:
++ drm_output_destroy(&output->base);
++ return -1;
++ /* no fallthrough! */
+
+- wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
+- drmModeSetPlane(backend->drm.fd,
+- sprite->plane_id,
+- output->crtc_id, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0);
+- drm_output_release_fb(output, sprite->current);
+- drm_output_release_fb(output, sprite->next);
+- weston_plane_release(&sprite->plane);
+- free(sprite);
+- }
++err_init:
++ drmModeFreeConnector(connector);
++ return -1;
+ }
+
+ static int
+@@ -2718,24 +5042,25 @@ create_outputs(struct drm_backend *b, struct udev_device *drm_device)
+ b->max_height = resources->max_height;
+
+ for (i = 0; i < resources->count_connectors; i++) {
++ int ret;
++
+ connector = drmModeGetConnector(b->drm.fd,
+ resources->connectors[i]);
+ if (connector == NULL)
+ continue;
+
+- if (connector->connection == DRM_MODE_CONNECTED &&
+- (b->connector == 0 ||
+- connector->connector_id == b->connector)) {
+- if (create_output_for_connector(b, resources,
+- connector, drm_device) < 0) {
+- drmModeFreeConnector(connector);
+- continue;
+- }
++ if (connector->connection == DRM_MODE_CONNECTED) {
++ ret = create_output_for_connector(b, resources,
++ connector, drm_device);
++ if (ret < 0)
++ weston_log("failed to create new connector\n");
+ } else {
+ drmModeFreeConnector(connector);
+ }
+ }
+
++ drm_backend_update_unused_outputs(b, resources);
++
+ if (wl_list_empty(&b->compositor->output_list) &&
+ wl_list_empty(&b->compositor->pending_output_list))
+ weston_log("No currently active connector found.\n");
+@@ -2779,11 +5104,6 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
+ continue;
+ }
+
+- if (b->connector && (b->connector != connector_id)) {
+- drmModeFreeConnector(connector);
+- continue;
+- }
+-
+ connected[i] = connector_id;
+
+ if (drm_output_find_by_connector(b, connector_id)) {
+@@ -2832,6 +5152,8 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
+ drm_output_destroy(&output->base);
+ }
+
++ drm_backend_update_unused_outputs(b, resources);
++
+ free(connected);
+ drmModeFreeResources(resources);
+ }
+@@ -2885,6 +5207,8 @@ drm_destroy(struct weston_compositor *ec)
+ wl_event_source_remove(b->udev_drm_source);
+ wl_event_source_remove(b->drm_source);
+
++ b->shutting_down = true;
++
+ destroy_sprites(b);
+
+ weston_compositor_shutdown(ec);
+@@ -2892,9 +5216,16 @@ drm_destroy(struct weston_compositor *ec)
+ if (b->gbm)
+ gbm_device_destroy(b->gbm);
+
++ udev_monitor_unref(b->udev_monitor);
++ udev_unref(b->udev);
++
+ weston_launcher_destroy(ec->launcher);
+
++ wl_array_release(&b->unused_crtcs);
++ wl_array_release(&b->unused_connectors);
++
+ close(b->drm.fd);
++ free(b->drm.filename);
+ free(b);
+ }
+
+@@ -2903,13 +5234,14 @@ session_notify(struct wl_listener *listener, void *data)
+ {
+ struct weston_compositor *compositor = data;
+ struct drm_backend *b = to_drm_backend(compositor);
+- struct drm_sprite *sprite;
++ struct drm_plane *plane;
+ struct drm_output *output;
+
+ if (compositor->session_active) {
+ weston_log("activating session\n");
+ weston_compositor_wake(compositor);
+ weston_compositor_damage_all(compositor);
++ b->state_invalid = true;
+ udev_input_enable(&b->input);
+ } else {
+ weston_log("deactivating session\n");
+@@ -2926,19 +5258,80 @@ session_notify(struct wl_listener *listener, void *data)
+ * pending frame callbacks. */
+
+ wl_list_for_each(output, &compositor->output_list, base.link) {
+- output->base.repaint_needed = 0;
+- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
++ output->base.repaint_needed = false;
++ if (output->cursor_plane)
++ drmModeSetCursor(b->drm.fd, output->crtc_id,
++ 0, 0, 0);
+ }
+
+ output = container_of(compositor->output_list.next,
+ struct drm_output, base.link);
+
+- wl_list_for_each(sprite, &b->sprite_list, link)
++ wl_list_for_each(plane, &b->plane_list, link) {
++ if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
++ continue;
++
+ drmModeSetPlane(b->drm.fd,
+- sprite->plane_id,
++ plane->plane_id,
+ output->crtc_id, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0);
+- };
++ }
++ }
++}
++
++/**
++ * Determines whether or not a device is capable of modesetting. If successful,
++ * sets b->drm.fd and b->drm.filename to the opened device.
++ */
++static bool
++drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
++{
++ const char *filename = udev_device_get_devnode(device);
++ const char *sysnum = udev_device_get_sysnum(device);
++ drmModeRes *res;
++ int id, fd;
++
++ if (!filename)
++ return false;
++
++ fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
++ if (fd < 0)
++ return false;
++
++ res = drmModeGetResources(fd);
++ if (!res)
++ goto out_fd;
++
++ if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
++ res->count_encoders <= 0)
++ goto out_res;
++
++ if (sysnum)
++ id = atoi(sysnum);
++ if (!sysnum || id < 0) {
++ weston_log("couldn't get sysnum for device %s\n", filename);
++ goto out_res;
++ }
++
++ /* We can be called successfully on multiple devices; if we have,
++ * clean up old entries. */
++ if (b->drm.fd >= 0)
++ weston_launcher_close(b->compositor->launcher, b->drm.fd);
++ free(b->drm.filename);
++
++ b->drm.fd = fd;
++ b->drm.id = id;
++ b->drm.filename = strdup(filename);
++
++ drmModeFreeResources(res);
++
++ return true;
++
++out_res:
++ drmModeFreeResources(res);
++out_fd:
++ weston_launcher_close(b->compositor->launcher, fd);
++ return false;
+ }
+
+ /*
+@@ -2947,6 +5340,9 @@ session_notify(struct wl_listener *listener, void *data)
+ * function loops over all devices and tries to find a PCI device with the
+ * boot_vga sysfs attribute set to 1.
+ * If no such device is found, the first DRM device reported by udev is used.
++ * Devices are also vetted to make sure they are are capable of modesetting,
++ * rather than pure render nodes (GPU with no display), or pure
++ * memory-allocation devices (VGEM).
+ */
+ static struct udev_device*
+ find_primary_gpu(struct drm_backend *b, const char *seat)
+@@ -2963,6 +5359,8 @@ find_primary_gpu(struct drm_backend *b, const char *seat)
+ udev_enumerate_scan_devices(e);
+ drm_device = NULL;
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
++ bool is_boot_vga = false;
++
+ path = udev_list_entry_get_name(entry);
+ device = udev_device_new_from_syspath(b->udev, path);
+ if (!device)
+@@ -2979,27 +5377,77 @@ find_primary_gpu(struct drm_backend *b, const char *seat)
+ "pci", NULL);
+ if (pci) {
+ id = udev_device_get_sysattr_value(pci, "boot_vga");
+- if (id && !strcmp(id, "1")) {
+- if (drm_device)
+- udev_device_unref(drm_device);
+- drm_device = device;
+- break;
+- }
++ if (id && !strcmp(id, "1"))
++ is_boot_vga = true;
+ }
+
+- if (!drm_device)
+- drm_device = device;
+- else
++ /* If we already have a modesetting-capable device, and this
++ * device isn't our boot-VGA device, we aren't going to use
++ * it. */
++ if (!is_boot_vga && drm_device) {
++ udev_device_unref(device);
++ continue;
++ }
++
++ /* Make sure this device is actually capable of modesetting;
++ * if this call succeeds, b->drm.{fd,filename} will be set,
++ * and any old values freed. */
++ if (!drm_device_is_kms(b, device)) {
+ udev_device_unref(device);
++ continue;
++ }
++
++ /* There can only be one boot_vga device, and we try to use it
++ * at all costs. */
++ if (is_boot_vga) {
++ if (drm_device)
++ udev_device_unref(drm_device);
++ drm_device = device;
++ break;
++ }
++
++ /* Per the (!is_boot_vga && drm_device) test above, we only
++ * trump existing saved devices with boot-VGA devices, so if
++ * we end up here, this must be the first device we've seen. */
++ assert(!drm_device);
++ drm_device = device;
+ }
+
++ /* If we're returning a device to use, we must have an open FD for
++ * it. */
++ assert(!!drm_device == (b->drm.fd >= 0));
++
+ udev_enumerate_unref(e);
+ return drm_device;
+ }
+
++static struct udev_device *
++open_specific_drm_device(struct drm_backend *b, const char *name)
++{
++ struct udev_device *device;
++
++ device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
++ if (!device) {
++ weston_log("ERROR: could not open DRM device '%s'\n", name);
++ return NULL;
++ }
++
++ if (!drm_device_is_kms(b, device)) {
++ udev_device_unref(device);
++ weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
++ return NULL;
++ }
++
++ /* If we're returning a device to use, we must have an open FD for
++ * it. */
++ assert(b->drm.fd >= 0);
++
++ return device;
++}
++
+ static void
+-planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+- void *data)
++planes_binding(struct weston_keyboard *keyboard, uint32_t time,
++ uint32_t key, void *data)
+ {
+ struct drm_backend *b = data;
+
+@@ -3045,7 +5493,8 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
+ if (!output->recorder)
+ return;
+
+- ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
++ ret = drmPrimeHandleToFD(b->drm.fd,
++ output->scanout_plane->state_cur->fb->handle,
+ DRM_CLOEXEC, &fd);
+ if (ret) {
+ weston_log("[libva recorder] "
+@@ -3054,7 +5503,7 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
+ }
+
+ ret = vaapi_recorder_frame(output->recorder, fd,
+- output->current->stride);
++ output->scanout_plane->state_cur->fb->stride);
+ if (ret < 0) {
+ weston_log("[libva recorder] aborted: %m\n");
+ recorder_destroy(output);
+@@ -3079,8 +5528,8 @@ create_recorder(struct drm_backend *b, int width, int height,
+ }
+
+ static void
+-recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+- void *data)
++recorder_binding(struct weston_keyboard *keyboard, uint32_t time,
++ uint32_t key, void *data)
+ {
+ struct drm_backend *b = data;
+ struct drm_output *output;
+@@ -3121,8 +5570,8 @@ recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+ }
+ #else
+ static void
+-recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+- void *data)
++recorder_binding(struct weston_keyboard *keyboard, uint32_t time,
++ uint32_t key, void *data)
+ {
+ weston_log("Compiled without libva support\n");
+ }
+@@ -3173,8 +5622,8 @@ switch_to_gl_renderer(struct drm_backend *b)
+ }
+
+ static void
+-renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
+- uint32_t key, void *data)
++renderer_switch_binding(struct weston_keyboard *keyboard,
++ uint32_t time, uint32_t key, void *data)
+ {
+ struct drm_backend *b =
+ to_drm_backend(keyboard->seat->compositor);
+@@ -3195,7 +5644,6 @@ drm_backend_create(struct weston_compositor *compositor,
+ struct drm_backend *b;
+ struct udev_device *drm_device;
+ struct wl_event_loop *loop;
+- const char *path;
+ const char *seat_id = default_seat;
+ int ret;
+
+@@ -3205,6 +5653,11 @@ drm_backend_create(struct weston_compositor *compositor,
+ if (b == NULL)
+ return NULL;
+
++ b->state_invalid = true;
++ b->drm.fd = -1;
++ wl_array_init(&b->unused_crtcs);
++ wl_array_init(&b->unused_connectors);
++
+ /*
+ * KMS support for hardware planes cannot properly synchronize
+ * without nuclear page flip. Without nuclear/atomic, hw plane
+@@ -3218,6 +5671,9 @@ drm_backend_create(struct weston_compositor *compositor,
+ b->sprites_are_broken = 1;
+ b->compositor = compositor;
+ b->use_pixman = config->use_pixman;
++ b->pageflip_timeout = config->pageflip_timeout;
++
++ compositor->backend = &b->base;
+
+ if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
+ goto err_compositor;
+@@ -3229,8 +5685,9 @@ drm_backend_create(struct weston_compositor *compositor,
+ compositor->launcher = weston_launcher_connect(compositor, config->tty,
+ seat_id, true);
+ if (compositor->launcher == NULL) {
+- weston_log("fatal: drm backend should be run "
+- "using weston-launch binary or as root\n");
++ weston_log("fatal: drm backend should be run using "
++ "weston-launch binary, or your system should "
++ "provide the logind D-Bus API.\n");
+ goto err_compositor;
+ }
+
+@@ -3243,14 +5700,16 @@ drm_backend_create(struct weston_compositor *compositor,
+ b->session_listener.notify = session_notify;
+ wl_signal_add(&compositor->session_signal, &b->session_listener);
+
+- drm_device = find_primary_gpu(b, seat_id);
++ if (config->specific_device)
++ drm_device = open_specific_drm_device(b, config->specific_device);
++ else
++ drm_device = find_primary_gpu(b, seat_id);
+ if (drm_device == NULL) {
+ weston_log("no drm device found\n");
+ goto err_udev;
+ }
+- path = udev_device_get_syspath(drm_device);
+
+- if (init_drm(b, drm_device) < 0) {
++ if (init_kms_caps(b) < 0) {
+ weston_log("failed to initialize kms\n");
+ goto err_udev_dev;
+ }
+@@ -3262,21 +5721,20 @@ drm_backend_create(struct weston_compositor *compositor,
+ }
+ } else {
+ if (init_egl(b) < 0) {
+- weston_log("failed to initialize egl, use pixman\n");
+- if (init_pixman(b) < 0) {
+- weston_log("failed to initialize pixman renderer\n");
+- goto err_udev_dev;
+- }
+- b->use_pixman = 1;
++ weston_log("failed to initialize egl\n");
++ goto err_udev_dev;
+ }
+ }
+
+ b->base.destroy = drm_destroy;
+ b->base.restore = drm_restore;
++ b->base.repaint_begin = drm_repaint_begin;
++ b->base.repaint_flush = drm_repaint_flush;
++ b->base.repaint_cancel = drm_repaint_cancel;
+
+ weston_setup_vt_switch_bindings(compositor);
+
+- wl_list_init(&b->sprite_list);
++ wl_list_init(&b->plane_list);
+ create_sprites(b);
+
+ if (udev_input_init(&b->input,
+@@ -3286,10 +5744,8 @@ drm_backend_create(struct weston_compositor *compositor,
+ goto err_sprite;
+ }
+
+- b->connector = config->connector;
+-
+ if (create_outputs(b, drm_device) < 0) {
+- weston_log("failed to create output for %s\n", path);
++ weston_log("failed to create output for %s\n", b->drm.filename);
+ goto err_udev_input;
+ }
+
+@@ -3298,8 +5754,6 @@ drm_backend_create(struct weston_compositor *compositor,
+ if (!b->cursors_are_broken)
+ compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
+
+- path = NULL;
+-
+ loop = wl_display_get_event_loop(compositor->wl_display);
+ b->drm_source =
+ wl_event_loop_add_fd(loop, b->drm.fd,
+@@ -3341,8 +5795,6 @@ drm_backend_create(struct weston_compositor *compositor,
+ "support failed.\n");
+ }
+
+- compositor->backend = &b->base;
+-
+ ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
+ &api, sizeof(api));
+
+diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
+index 2e2995a..838e937 100644
+--- a/libweston/compositor-drm.h
++++ b/libweston/compositor-drm.h
+@@ -35,7 +35,7 @@
+ extern "C" {
+ #endif
+
+-#define WESTON_DRM_BACKEND_CONFIG_VERSION 2
++#define WESTON_DRM_BACKEND_CONFIG_VERSION 3
+
+ struct libinput_device;
+
+@@ -138,6 +138,20 @@ struct weston_drm_backend_config {
+ */
+ void (*configure_device)(struct weston_compositor *compositor,
+ struct libinput_device *device);
++
++ /** Maximum duration for a pageflip event to arrive, after which the
++ * compositor will consider the DRM driver crashed and will try to exit
++ * cleanly.
++ *
++ * It is exprimed in milliseconds, 0 means disabled. */
++ uint32_t pageflip_timeout;
++
++ /** Specific DRM device to open
++ *
++ * A DRM device name, like "card0", to open. If NULL, use heuristics
++ * based on seat names and boot_vga to find the right device.
++ */
++ char *specific_device;
+ };
+
+ #ifdef __cplusplus
+diff --git a/libweston/compositor-fbdev.c b/libweston/compositor-fbdev.c
+index 44f0cf5..32d71e0 100644
+--- a/libweston/compositor-fbdev.c
++++ b/libweston/compositor-fbdev.c
+@@ -118,7 +118,8 @@ fbdev_output_start_repaint_loop(struct weston_output *output)
+ }
+
+ static int
+-fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
++fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct fbdev_output *output = to_fbdev_output(base);
+ struct weston_compositor *ec = output->base.compositor;
+@@ -693,7 +694,7 @@ session_notify(struct wl_listener *listener, void *data)
+
+ wl_list_for_each(output,
+ &compositor->output_list, link) {
+- output->repaint_needed = 0;
++ output->repaint_needed = false;
+ }
+ }
+ }
+diff --git a/libweston/compositor-headless.c b/libweston/compositor-headless.c
+index a1aec6d..9e42e7f 100644
+--- a/libweston/compositor-headless.c
++++ b/libweston/compositor-headless.c
+@@ -92,7 +92,8 @@ finish_frame_handler(void *data)
+
+ static int
+ headless_output_repaint(struct weston_output *output_base,
+- pixman_region32_t *damage)
++ pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct headless_output *output = to_headless_output(output_base);
+ struct weston_compositor *ec = output->base.compositor;
+diff --git a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c
+index d9668e8..091472b 100644
+--- a/libweston/compositor-rdp.c
++++ b/libweston/compositor-rdp.c
+@@ -355,7 +355,8 @@ rdp_output_start_repaint_loop(struct weston_output *output)
+ }
+
+ static int
+-rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
++rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct rdp_output *output = container_of(output_base, struct rdp_output, base);
+ struct weston_compositor *ec = output->base.compositor;
+diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c
+index 9d35ef7..ebdbd13 100644
+--- a/libweston/compositor-wayland.c
++++ b/libweston/compositor-wayland.c
+@@ -488,7 +488,8 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
+ #ifdef ENABLE_EGL
+ static int
+ wayland_output_repaint_gl(struct weston_output *output_base,
+- pixman_region32_t *damage)
++ pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct wayland_output *output = to_wayland_output(output_base);
+ struct weston_compositor *ec = output->base.compositor;
+@@ -595,7 +596,8 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
+
+ static int
+ wayland_output_repaint_pixman(struct weston_output *output_base,
+- pixman_region32_t *damage)
++ pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct wayland_output *output = to_wayland_output(output_base);
+ struct wayland_backend *b =
+diff --git a/libweston/compositor-x11.c b/libweston/compositor-x11.c
+index f9cb461..02cdf3e 100644
+--- a/libweston/compositor-x11.c
++++ b/libweston/compositor-x11.c
+@@ -389,7 +389,8 @@ x11_output_start_repaint_loop(struct weston_output *output)
+
+ static int
+ x11_output_repaint_gl(struct weston_output *output_base,
+- pixman_region32_t *damage)
++ pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct x11_output *output = to_x11_output(output_base);
+ struct weston_compositor *ec = output->base.compositor;
+@@ -457,7 +458,8 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
+
+ static int
+ x11_output_repaint_shm(struct weston_output *output_base,
+- pixman_region32_t *damage)
++ pixman_region32_t *damage,
++ void *repaint_data)
+ {
+ struct x11_output *output = to_x11_output(output_base);
+ struct weston_compositor *ec = output->base.compositor;
+diff --git a/libweston/compositor.c b/libweston/compositor.c
+index 9ded23f..fb647da 100644
+--- a/libweston/compositor.c
++++ b/libweston/compositor.c
+@@ -2254,7 +2254,7 @@ weston_output_take_feedback_list(struct weston_output *output,
+ }
+
+ static int
+-weston_output_repaint(struct weston_output *output)
++weston_output_repaint(struct weston_output *output, void *repaint_data)
+ {
+ struct weston_compositor *ec = output->compositor;
+ struct weston_view *ev;
+@@ -2273,7 +2273,7 @@ weston_output_repaint(struct weston_output *output)
+ weston_compositor_build_view_list(ec);
+
+ if (output->assign_planes && !output->disable_planes) {
+- output->assign_planes(output);
++ output->assign_planes(output, repaint_data);
+ } else {
+ wl_list_for_each(ev, &ec->view_list, link) {
+ weston_view_move_to_plane(ev, &ec->primary_plane);
+@@ -2306,11 +2306,13 @@ weston_output_repaint(struct weston_output *output)
+ if (output->dirty)
+ weston_output_update_matrix(output);
+
+- r = output->repaint(output, &output_damage);
++ r = output->repaint(output, &output_damage, repaint_data);
+
+ pixman_region32_fini(&output_damage);
+
+- output->repaint_needed = 0;
++ output->repaint_needed = false;
++ if (r == 0)
++ output->repaint_status = REPAINT_AWAITING_COMPLETION;
+
+ weston_compositor_repick(ec);
+
+@@ -2332,16 +2334,25 @@ weston_output_repaint(struct weston_output *output)
+ static void
+ weston_output_schedule_repaint_reset(struct weston_output *output)
+ {
+- output->repaint_scheduled = 0;
++ output->repaint_status = REPAINT_NOT_SCHEDULED;
+ TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
+ }
+
+ static int
+-output_repaint_timer_handler(void *data)
++weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
++ void *repaint_data)
+ {
+- struct weston_output *output = data;
+ struct weston_compositor *compositor = output->compositor;
+- int ret;
++ int ret = 0;
++ int64_t msec_to_repaint;
++
++ /* We're not ready yet; come back to make a decision later. */
++ if (output->repaint_status != REPAINT_SCHEDULED)
++ return ret;
++
++ msec_to_repaint = timespec_sub_to_msec(&output->next_repaint, now);
++ if (msec_to_repaint > 1)
++ return ret;
+
+ /* If we're sleeping, drop the repaint machinery entirely; we will
+ * explicitly repaint all outputs when we come back. */
+@@ -2356,15 +2367,92 @@ output_repaint_timer_handler(void *data)
+
+ /* If repaint fails, we aren't going to get weston_output_finish_frame
+ * to trigger a new repaint, so drop it from repaint and hope
+- * something schedules a successful repaint later. */
+- ret = weston_output_repaint(output);
++ * something schedules a successful repaint later. As repainting may
++ * take some time, re-read our clock as a courtesy to the next
++ * output. */
++ ret = weston_output_repaint(output, repaint_data);
++ weston_compositor_read_presentation_clock(compositor, now);
+ if (ret != 0)
+ goto err;
+
+- return 0;
++ return ret;
+
+ err:
+ weston_output_schedule_repaint_reset(output);
++ return ret;
++}
++
++static void
++output_repaint_timer_arm(struct weston_compositor *compositor)
++{
++ struct weston_output *output;
++ bool any_should_repaint = false;
++ struct timespec now;
++ int64_t msec_to_next;
++
++ weston_compositor_read_presentation_clock(compositor, &now);
++
++ wl_list_for_each(output, &compositor->output_list, link) {
++ int64_t msec_to_this;
++
++ if (output->repaint_status != REPAINT_SCHEDULED)
++ continue;
++
++ msec_to_this = timespec_sub_to_msec(&output->next_repaint,
++ &now);
++ if (!any_should_repaint || msec_to_this < msec_to_next)
++ msec_to_next = msec_to_this;
++
++ any_should_repaint = true;
++ }
++
++ if (!any_should_repaint)
++ return;
++
++ /* Even if we should repaint immediately, add the minimum 1 ms delay.
++ * This is a workaround to allow coalescing multiple output repaints
++ * particularly from weston_output_finish_frame()
++ * into the same call, which would not happen if we called
++ * output_repaint_timer_handler() directly.
++ */
++ if (msec_to_next < 1)
++ msec_to_next = 1;
++
++ wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
++}
++
++static int
++output_repaint_timer_handler(void *data)
++{
++ struct weston_compositor *compositor = data;
++ struct weston_output *output;
++ struct timespec now;
++ void *repaint_data = NULL;
++ int ret;
++
++ weston_compositor_read_presentation_clock(compositor, &now);
++
++ if (compositor->backend->repaint_begin)
++ repaint_data = compositor->backend->repaint_begin(compositor);
++
++ wl_list_for_each(output, &compositor->output_list, link) {
++ ret = weston_output_maybe_repaint(output, &now, repaint_data);
++ if (ret)
++ break;
++ }
++
++ if (ret == 0) {
++ if (compositor->backend->repaint_flush)
++ compositor->backend->repaint_flush(compositor,
++ repaint_data);
++ } else {
++ if (compositor->backend->repaint_cancel)
++ compositor->backend->repaint_cancel(compositor,
++ repaint_data);
++ }
++
++ output_repaint_timer_arm(compositor);
++
+ return 0;
+ }
+
+@@ -2376,47 +2464,59 @@ weston_output_finish_frame(struct weston_output *output,
+ struct weston_compositor *compositor = output->compositor;
+ int32_t refresh_nsec;
+ struct timespec now;
+- struct timespec gone;
+- int msec;
++ int64_t msec_rel;
+
+ TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
+ TLP_VBLANK(stamp), TLP_END);
+
++ assert(output->repaint_status == REPAINT_AWAITING_COMPLETION);
++ assert(stamp || (presented_flags & WP_PRESENTATION_FEEDBACK_INVALID));
++
++ weston_compositor_read_presentation_clock(compositor, &now);
++
++ /* If we haven't been supplied any timestamp at all, we don't have a
++ * timebase to work against, so any delay just wastes time. Push a
++ * repaint as soon as possible so we can get on with it. */
++ if (!stamp) {
++ output->next_repaint = now;
++ goto out;
++ }
++
+ refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
+ weston_presentation_feedback_present_list(&output->feedback_list,
+ output, refresh_nsec, stamp,
+ output->msc,
+ presented_flags);
+
+- output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
++ output->frame_time = timespec_to_msec(stamp);
+
+- weston_compositor_read_presentation_clock(compositor, &now);
+- timespec_sub(&gone, &now, stamp);
+- msec = (refresh_nsec - timespec_to_nsec(&gone)) / 1000000; /* floor */
+- msec -= compositor->repaint_msec;
++ timespec_add_nsec(&output->next_repaint, stamp, refresh_nsec);
++ timespec_add_msec(&output->next_repaint, &output->next_repaint,
++ -compositor->repaint_msec);
++ msec_rel = timespec_sub_to_msec(&output->next_repaint, &now);
+
+- if (msec < -1000 || msec > 1000) {
++ if (msec_rel < -1000 || msec_rel > 1000) {
+ static bool warned;
+
+ if (!warned)
+ weston_log("Warning: computed repaint delay is "
+- "insane: %d msec\n", msec);
++ "insane: %lld msec\n", (long long) msec_rel);
+ warned = true;
+
+- msec = 0;
++ output->next_repaint = now;
+ }
+
+ /* Called from restart_repaint_loop and restart happens already after
+ * the deadline given by repaint_msec? In that case we delay until
+ * the deadline of the next frame, to give clients a more predictable
+ * timing of the repaint cycle to lock on. */
+- if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec < 0)
+- msec += refresh_nsec / 1000000;
++ if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec_rel < 0)
++ timespec_add_nsec(&output->next_repaint, &output->next_repaint,
++ refresh_nsec);
+
+- if (msec < 1)
+- output_repaint_timer_handler(output);
+- else
+- wl_event_source_timer_update(output->repaint_timer, msec);
++out:
++ output->repaint_status = REPAINT_SCHEDULED;
++ output_repaint_timer_arm(compositor);
+ }
+
+ static void
+@@ -2424,6 +2524,8 @@ idle_repaint(void *data)
+ {
+ struct weston_output *output = data;
+
++ assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE);
++ output->repaint_status = REPAINT_AWAITING_COMPLETION;
+ output->start_repaint_loop(output);
+ }
+
+@@ -2538,12 +2640,17 @@ weston_output_schedule_repaint(struct weston_output *output)
+ TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
+
+ loop = wl_display_get_event_loop(compositor->wl_display);
+- output->repaint_needed = 1;
+- if (output->repaint_scheduled)
++ output->repaint_needed = true;
++
++ /* If we already have a repaint scheduled for our idle handler,
++ * no need to set it again. If the repaint has been called but
++ * not finished, then weston_output_finish_frame() will notice
++ * that a repaint is needed and schedule one. */
++ if (output->repaint_status != REPAINT_NOT_SCHEDULED)
+ return;
+
++ output->repaint_status = REPAINT_BEGIN_FROM_IDLE;
+ wl_event_loop_add_idle(loop, idle_repaint, output);
+- output->repaint_scheduled = 1;
+ TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
+ }
+
+@@ -4400,8 +4507,6 @@ weston_output_transform_coordinate(struct weston_output *output,
+ static void
+ weston_output_enable_undo(struct weston_output *output)
+ {
+- wl_event_source_remove(output->repaint_timer);
+-
+ wl_global_destroy(output->global);
+
+ pixman_region32_fini(&output->region);
+@@ -4583,7 +4688,6 @@ weston_output_enable(struct weston_output *output)
+ {
+ struct weston_compositor *c = output->compositor;
+ struct weston_output *iterator;
+- struct wl_event_loop *loop;
+ int x = 0, y = 0;
+
+ assert(output->enable);
+@@ -4624,10 +4728,6 @@ weston_output_enable(struct weston_output *output)
+ wl_list_init(&output->feedback_list);
+ wl_list_init(&output->link);
+
+- loop = wl_display_get_event_loop(c->wl_display);
+- output->repaint_timer = wl_event_loop_add_timer(loop,
+- output_repaint_timer_handler, output);
+-
+ /* Invert the output id pool and look for the lowest numbered
+ * switch (the least significant bit). Take that bit's position
+ * as our ID, and mark it used in the compositor's output_id_pool.
+@@ -5129,6 +5229,9 @@ weston_compositor_create(struct wl_display *display, void *user_data)
+
+ loop = wl_display_get_event_loop(ec->wl_display);
+ ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
++ ec->repaint_timer =
++ wl_event_loop_add_timer(loop, output_repaint_timer_handler,
++ ec);
+
+ weston_layer_init(&ec->fade_layer, ec);
+ weston_layer_init(&ec->cursor_layer, ec);
+diff --git a/libweston/compositor.h b/libweston/compositor.h
+index 08e728a..6070c77 100644
+--- a/libweston/compositor.h
++++ b/libweston/compositor.h
+@@ -170,9 +170,23 @@ struct weston_output {
+ pixman_region32_t region;
+
+ pixman_region32_t previous_damage;
+- int repaint_needed;
+- int repaint_scheduled;
+- struct wl_event_source *repaint_timer;
++
++ /** True if damage has occurred since the last repaint for this output;
++ * if set, a repaint will eventually occur. */
++ bool repaint_needed;
++
++ /** State of the repaint loop */
++ enum {
++ REPAINT_NOT_SCHEDULED = 0, /**< idle; no repaint will occur */
++ REPAINT_BEGIN_FROM_IDLE, /**< start_repaint_loop scheduled */
++ REPAINT_SCHEDULED, /**< repaint is scheduled to occur */
++ REPAINT_AWAITING_COMPLETION, /**< last repaint not yet finished */
++ } repaint_status;
++
++ /** If repaint_status is REPAINT_SCHEDULED, contains the time the
++ * next repaint should be run */
++ struct timespec next_repaint;
++
+ struct weston_output_zoom zoom;
+ int dirty;
+ struct wl_signal frame_signal;
+@@ -198,9 +212,10 @@ struct weston_output {
+
+ void (*start_repaint_loop)(struct weston_output *output);
+ int (*repaint)(struct weston_output *output,
+- pixman_region32_t *damage);
++ pixman_region32_t *damage,
++ void *repaint_data);
+ void (*destroy)(struct weston_output *output);
+- void (*assign_planes)(struct weston_output *output);
++ void (*assign_planes)(struct weston_output *output, void *repaint_data);
+ int (*switch_mode)(struct weston_output *output, struct weston_mode *mode);
+
+ /* backlight values are on 0-255 range, where higher is brighter */
+@@ -790,6 +805,39 @@ struct weston_backend_config {
+ struct weston_backend {
+ void (*destroy)(struct weston_compositor *compositor);
+ void (*restore)(struct weston_compositor *compositor);
++
++ /** Begin a repaint sequence
++ *
++ * Provides the backend with explicit markers around repaint
++ * sequences, which may allow the backend to aggregate state
++ * application. This call will be bracketed by the repaint_flush (on
++ * success), or repaint_cancel (when any output in the grouping fails
++ * repaint).
++ *
++ * Returns an opaque pointer, which the backend may use as private
++ * data referring to the repaint cycle.
++ */
++ void * (*repaint_begin)(struct weston_compositor *compositor);
++
++ /** Cancel a repaint sequence
++ *
++ * Cancels a repaint sequence, when an error has occurred during
++ * one output's repaint; see repaint_begin.
++ *
++ * @param repaint_data Data returned by repaint_begin
++ */
++ void (*repaint_cancel)(struct weston_compositor *compositor,
++ void *repaint_data);
++
++ /** Conclude a repaint sequence
++ *
++ * Called on successful completion of a repaint sequence; see
++ * repaint_begin.
++ *
++ * @param repaint_data Data returned by repaint_begin
++ */
++ void (*repaint_flush)(struct weston_compositor *compositor,
++ void *repaint_data);
+ };
+
+ struct weston_desktop_xwayland;
+@@ -845,6 +893,7 @@ struct weston_compositor {
+ struct wl_event_source *idle_source;
+ uint32_t idle_inhibit;
+ int idle_time; /* timeout, s */
++ struct wl_event_source *repaint_timer;
+
+ const struct weston_pointer_grab_interface *default_pointer_grab;
+
+diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c
+new file mode 100644
+index 0000000..df84a9f
+--- /dev/null
++++ b/libweston/pixel-formats.c
+@@ -0,0 +1,430 @@
++/*
++ * Copyright © 2016 Collabora, Ltd.
++ *
++ * 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.
++ *
++ * Author: Daniel Stone <daniels@collabora.com>
++ */
++
++#include "config.h"
++
++#include <endian.h>
++#include <inttypes.h>
++#include <stdbool.h>
++#include <unistd.h>
++#include <drm_fourcc.h>
++
++#include "helpers.h"
++#include "wayland-util.h"
++#include "pixel-formats.h"
++
++#if ENABLE_EGL
++#include <EGL/egl.h>
++#include <EGL/eglext.h>
++#include <GLES2/gl2.h>
++#include <GLES2/gl2ext.h>
++#define GL_FORMAT(fmt) .gl_format = (fmt)
++#define GL_TYPE(type) .gl_type = (type)
++#define SAMPLER_TYPE(type) .sampler_type = (type)
++#else
++#define GL_FORMAT(fmt) .gl_format = 0
++#define GL_TYPE(type) .gl_type = 0
++#define SAMPLER_TYPE(type) .sampler_type = 0
++#endif
++
++#include "weston-egl-ext.h"
++
++/**
++ * Table of DRM formats supported by Weston; RGB, ARGB and YUV formats are
++ * supported. Indexed/greyscale formats, and formats not containing complete
++ * colour channels, are not supported.
++ */
++static const struct pixel_format_info pixel_format_table[] = {
++ {
++ .format = DRM_FORMAT_XRGB4444,
++ },
++ {
++ .format = DRM_FORMAT_ARGB4444,
++ .opaque_substitute = DRM_FORMAT_XRGB4444,
++ },
++ {
++ .format = DRM_FORMAT_XBGR4444,
++ },
++ {
++ .format = DRM_FORMAT_ABGR4444,
++ .opaque_substitute = DRM_FORMAT_XBGR4444,
++ },
++ {
++ .format = DRM_FORMAT_RGBX4444,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_RGBA4444,
++ .opaque_substitute = DRM_FORMAT_RGBX4444,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_BGRX4444,
++ },
++ {
++ .format = DRM_FORMAT_BGRA4444,
++ .opaque_substitute = DRM_FORMAT_BGRX4444,
++ },
++ {
++ .format = DRM_FORMAT_XRGB1555,
++ .depth = 15,
++ .bpp = 16,
++ },
++ {
++ .format = DRM_FORMAT_ARGB1555,
++ .opaque_substitute = DRM_FORMAT_XRGB1555,
++ },
++ {
++ .format = DRM_FORMAT_XBGR1555,
++ },
++ {
++ .format = DRM_FORMAT_ABGR1555,
++ .opaque_substitute = DRM_FORMAT_XBGR1555,
++ },
++ {
++ .format = DRM_FORMAT_RGBX5551,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_RGBA5551,
++ .opaque_substitute = DRM_FORMAT_RGBX5551,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_BGRX5551,
++ },
++ {
++ .format = DRM_FORMAT_BGRA5551,
++ .opaque_substitute = DRM_FORMAT_BGRX5551,
++ },
++ {
++ .format = DRM_FORMAT_RGB565,
++ .depth = 16,
++ .bpp = 16,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGB),
++ GL_TYPE(GL_UNSIGNED_SHORT_5_6_5),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_BGR565,
++ },
++ {
++ .format = DRM_FORMAT_RGB888,
++ },
++ {
++ .format = DRM_FORMAT_BGR888,
++ GL_FORMAT(GL_RGB),
++ GL_TYPE(GL_UNSIGNED_BYTE),
++ },
++ {
++ .format = DRM_FORMAT_XRGB8888,
++ .depth = 24,
++ .bpp = 32,
++ GL_FORMAT(GL_BGRA_EXT),
++ GL_TYPE(GL_UNSIGNED_BYTE),
++ },
++ {
++ .format = DRM_FORMAT_ARGB8888,
++ .opaque_substitute = DRM_FORMAT_XRGB8888,
++ .depth = 32,
++ .bpp = 32,
++ GL_FORMAT(GL_BGRA_EXT),
++ GL_TYPE(GL_UNSIGNED_BYTE),
++ },
++ {
++ .format = DRM_FORMAT_XBGR8888,
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_BYTE),
++ },
++ {
++ .format = DRM_FORMAT_ABGR8888,
++ .opaque_substitute = DRM_FORMAT_XBGR8888,
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_BYTE),
++ },
++ {
++ .format = DRM_FORMAT_RGBX8888,
++ },
++ {
++ .format = DRM_FORMAT_RGBA8888,
++ .opaque_substitute = DRM_FORMAT_RGBX8888,
++ },
++ {
++ .format = DRM_FORMAT_BGRX8888,
++ },
++ {
++ .format = DRM_FORMAT_BGRA8888,
++ .opaque_substitute = DRM_FORMAT_BGRX8888,
++ },
++ {
++ .format = DRM_FORMAT_XRGB2101010,
++ .depth = 30,
++ .bpp = 32,
++ },
++ {
++ .format = DRM_FORMAT_ARGB2101010,
++ .opaque_substitute = DRM_FORMAT_XRGB2101010,
++ },
++ {
++ .format = DRM_FORMAT_XBGR2101010,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_ABGR2101010,
++ .opaque_substitute = DRM_FORMAT_XBGR2101010,
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++ GL_FORMAT(GL_RGBA),
++ GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
++#endif
++ },
++ {
++ .format = DRM_FORMAT_RGBX1010102,
++ },
++ {
++ .format = DRM_FORMAT_RGBA1010102,
++ .opaque_substitute = DRM_FORMAT_RGBX1010102,
++ },
++ {
++ .format = DRM_FORMAT_BGRX1010102,
++ },
++ {
++ .format = DRM_FORMAT_BGRA1010102,
++ .opaque_substitute = DRM_FORMAT_BGRX1010102,
++ },
++ {
++ .format = DRM_FORMAT_YUYV,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
++ .num_planes = 1,
++ .hsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_YVYU,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
++ .num_planes = 1,
++ .chroma_order = ORDER_VU,
++ .hsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_UYVY,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
++ .num_planes = 1,
++ .luma_chroma_order = ORDER_CHROMA_LUMA,
++ .hsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_VYUY,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
++ .num_planes = 1,
++ .luma_chroma_order = ORDER_CHROMA_LUMA,
++ .chroma_order = ORDER_VU,
++ .hsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_NV12,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
++ .num_planes = 2,
++ .hsub = 2,
++ .vsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_NV21,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
++ .num_planes = 2,
++ .chroma_order = ORDER_VU,
++ .hsub = 2,
++ .vsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_NV16,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
++ .num_planes = 2,
++ .hsub = 2,
++ .vsub = 1,
++ },
++ {
++ .format = DRM_FORMAT_NV61,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
++ .num_planes = 2,
++ .chroma_order = ORDER_VU,
++ .hsub = 2,
++ .vsub = 1,
++ },
++ {
++ .format = DRM_FORMAT_NV24,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
++ .num_planes = 2,
++ },
++ {
++ .format = DRM_FORMAT_NV42,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
++ .num_planes = 2,
++ .chroma_order = ORDER_VU,
++ },
++ {
++ .format = DRM_FORMAT_YUV410,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .hsub = 4,
++ .vsub = 4,
++ },
++ {
++ .format = DRM_FORMAT_YVU410,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .chroma_order = ORDER_VU,
++ .hsub = 4,
++ .vsub = 4,
++ },
++ {
++ .format = DRM_FORMAT_YUV411,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .hsub = 4,
++ .vsub = 1,
++ },
++ {
++ .format = DRM_FORMAT_YVU411,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .chroma_order = ORDER_VU,
++ .hsub = 4,
++ .vsub = 1,
++ },
++ {
++ .format = DRM_FORMAT_YUV420,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .hsub = 2,
++ .vsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_YVU420,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .chroma_order = ORDER_VU,
++ .hsub = 2,
++ .vsub = 2,
++ },
++ {
++ .format = DRM_FORMAT_YUV422,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .hsub = 2,
++ .vsub = 1,
++ },
++ {
++ .format = DRM_FORMAT_YVU422,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .chroma_order = ORDER_VU,
++ .hsub = 2,
++ .vsub = 1,
++ },
++ {
++ .format = DRM_FORMAT_YUV444,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ },
++ {
++ .format = DRM_FORMAT_YVU444,
++ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
++ .num_planes = 3,
++ .chroma_order = ORDER_VU,
++ },
++};
++
++WL_EXPORT const struct pixel_format_info *
++pixel_format_get_info(uint32_t format)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) {
++ if (pixel_format_table[i].format == format)
++ return &pixel_format_table[i];
++ }
++
++ return NULL;
++}
++
++WL_EXPORT unsigned int
++pixel_format_get_plane_count(const struct pixel_format_info *info)
++{
++ return info->num_planes ? info->num_planes : 1;
++}
++
++WL_EXPORT bool
++pixel_format_is_opaque(const struct pixel_format_info *info)
++{
++ return !info->opaque_substitute;
++}
++
++WL_EXPORT const struct pixel_format_info *
++pixel_format_get_opaque_substitute(const struct pixel_format_info *info)
++{
++ if (!info->opaque_substitute)
++ return info;
++ else
++ return pixel_format_get_info(info->opaque_substitute);
++}
++
++WL_EXPORT unsigned int
++pixel_format_width_for_plane(const struct pixel_format_info *info,
++ unsigned int plane,
++ unsigned int width)
++{
++ /* We don't support any formats where the first plane is subsampled. */
++ if (plane == 0 || !info->hsub)
++ return width;
++
++ return width / info->hsub;
++}
++
++WL_EXPORT unsigned int
++pixel_format_height_for_plane(const struct pixel_format_info *info,
++ unsigned int plane,
++ unsigned int height)
++{
++ /* We don't support any formats where the first plane is subsampled. */
++ if (plane == 0 || !info->vsub)
++ return height;
++
++ return height / info->vsub;
++}
+diff --git a/libweston/pixel-formats.h b/libweston/pixel-formats.h
+new file mode 100644
+index 0000000..b16aae3
+--- /dev/null
++++ b/libweston/pixel-formats.h
+@@ -0,0 +1,194 @@
++/*
++ * Copyright © 2016 Collabora, Ltd.
++ *
++ * 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.
++ *
++ * Author: Daniel Stone <daniels@collabora.com>
++ */
++
++#include <inttypes.h>
++#include <stdbool.h>
++
++/**
++ * Contains information about pixel formats, mapping format codes from
++ * wl_shm and drm_fourcc.h (which are deliberately identical, but for the
++ * special cases of WL_SHM_ARGB8888 and WL_SHM_XRGB8888) into various
++ * sets of information. Helper functions are provided for dealing with these
++ * raw structures.
++ */
++struct pixel_format_info {
++ /** DRM/wl_shm format code */
++ uint32_t format;
++
++ /** If non-zero, number of planes in base (non-modified) format. */
++ int num_planes;
++
++ /** If format contains alpha channel, opaque equivalent of format,
++ * i.e. alpha channel replaced with X. */
++ uint32_t opaque_substitute;
++
++ /** How the format should be sampled, expressed in terms of tokens
++ * from the EGL_WL_bind_wayland_display extension. If not set,
++ * assumed to be either RGB or RGBA, depending on whether or not
++ * the format contains an alpha channel. The samplers may still
++ * return alpha even for opaque formats; users must manually set
++ * the alpha channel to 1.0 (or ignore it) if the format is
++ * opaque. */
++ uint32_t sampler_type;
++
++ /** GL format, if data can be natively/directly uploaded. Note that
++ * whilst DRM formats are little-endian unless explicitly specified,
++ * (i.e. DRM_FORMAT_ARGB8888 is stored BGRA as sequential bytes in
++ * memory), GL uses the sequential byte order, so that format maps to
++ * GL_BGRA_EXT plus GL_UNSIGNED_BYTE. To add to the confusion, the
++ * explicitly-sized types (e.g. GL_UNSIGNED_SHORT_5_5_5_1) read in
++ * machine-endian order, so for these types, the correspondence
++ * depends on endianness. */
++ int gl_format;
++
++ /** GL data type, if data can be natively/directly uploaded. */
++ int gl_type;
++
++ /** If set, this format can be used with the legacy drmModeAddFB()
++ * function (not AddFB2), using this and the bpp member. */
++ int depth;
++
++ /** See 'depth' member above. */
++ int bpp;
++
++ /** Horizontal subsampling; if non-zero, divide the width by this
++ * member to obtain the number of columns in the source buffer for
++ * secondary planes only. Stride is not affected by horizontal
++ * subsampling. */
++ int hsub;
++
++ /** Vertical subsampling; if non-zero, divide the height by this
++ * member to obtain the number of rows in the source buffer for
++ * secondary planes only. */
++ int vsub;
++
++ /* Ordering of chroma components. */
++ enum {
++ ORDER_UV = 0,
++ ORDER_VU,
++ } chroma_order;
++
++ /* If packed YUV (num_planes == 1), ordering of luma/chroma
++ * components. */
++ enum {
++ ORDER_LUMA_CHROMA = 0,
++ ORDER_CHROMA_LUMA,
++ } luma_chroma_order;
++};
++
++/**
++ * Get pixel format information for a DRM format code
++ *
++ * Given a DRM format code, return a pixel format info structure describing
++ * the properties of that format.
++ *
++ * @param format DRM format code to get info for
++ * @returns A pixel format structure (must not be freed), or NULL if the
++ * format could not be found
++ */
++const struct pixel_format_info *pixel_format_get_info(uint32_t format);
++
++/**
++ * Get number of planes used by a pixel format
++ *
++ * Given a pixel format info structure, return the number of planes
++ * required for a buffer. Note that this is not necessarily identical to
++ * the number of samplers required to be bound, as two views into a single
++ * plane are sometimes required.
++ *
++ * @param format Pixel format info structure
++ * @returns Number of planes required for the format
++ */
++unsigned int
++pixel_format_get_plane_count(const struct pixel_format_info *format);
++
++/**
++ * Determine if a pixel format is opaque or contains alpha
++ *
++ * Returns whether or not the pixel format is opaque, or contains a
++ * significant alpha channel. Note that the suggested EGL sampler type may
++ * still sample undefined data into the alpha channel; users must consider
++ * alpha as 1.0 if the format is opaque, and not rely on the sampler to
++ * return this when sampling from the alpha channel.
++ *
++ * @param format Pixel format info structure
++ * @returns True if the format is opaque, or false if it has significant alpha
++ */
++bool pixel_format_is_opaque(const struct pixel_format_info *format);
++
++/**
++ * Get compatible opaque equivalent for a format
++ *
++ * Given a pixel format info structure, return a format which is wholly
++ * compatible with the input format, but opaque, ignoring the alpha channel.
++ * If an alpha format is provided, but the content is known to all be opaque,
++ * then this can be used as a substitute to avoid blending.
++ *
++ * If the input format is opaque, this function will return the input format.
++ *
++ * @param format Pixel format info structure
++ * @returns A pixel format info structure for the compatible opaque substitute
++ */
++const struct pixel_format_info *
++pixel_format_get_opaque_substitute(const struct pixel_format_info *format);
++
++/**
++ * Return the effective sampling width for a given plane
++ *
++ * When horizontal subsampling is effective, a sampler bound to a secondary
++ * plane must bind the sampler with a smaller effective width. This function
++ * returns the effective width to use for the sampler, i.e. dividing by hsub.
++ *
++ * If horizontal subsampling is not in effect, this will be equal to the
++ * width.
++ *
++ * @param format Pixel format info structure
++ * @param plane Zero-indexed plane number
++ * @param width Width of the buffer
++ * @returns Effective width for sampling
++ */
++unsigned int
++pixel_format_width_for_plane(const struct pixel_format_info *format,
++ unsigned int plane,
++ unsigned int width);
++
++/**
++ * Return the effective sampling height for a given plane
++ *
++ * When vertical subsampling is in effect, a sampler bound to a secondary
++ * plane must bind the sampler with a smaller effective height. This function
++ * returns the effective height to use for the sampler, i.e. dividing by vsub.
++ *
++ * If vertical subsampling is not in effect, this will be equal to the height.
++ *
++ * @param format Pixel format info structure
++ * @param plane Zero-indexed plane number
++ * @param height Height of the buffer
++ * @returns Effective width for sampling
++ */
++unsigned int
++pixel_format_height_for_plane(const struct pixel_format_info *format,
++ unsigned int plane,
++ unsigned int height);
+diff --git a/shared/timespec-util.h b/shared/timespec-util.h
+index edd4ec1..ca0156a 100644
+--- a/shared/timespec-util.h
++++ b/shared/timespec-util.h
+@@ -28,6 +28,8 @@
+
+ #include <stdint.h>
+ #include <assert.h>
++#include <time.h>
++#include <stdbool.h>
+
+ #define NSEC_PER_SEC 1000000000
+
+@@ -49,6 +51,39 @@ timespec_sub(struct timespec *r,
+ }
+ }
+
++/* Add a nanosecond value to a timespec
++ *
++ * \param r[out] result: a + b
++ * \param a[in] base operand as timespec
++ * \param b[in] operand in nanoseconds
++ */
++static inline void
++timespec_add_nsec(struct timespec *r, const struct timespec *a, int64_t b)
++{
++ r->tv_sec = a->tv_sec + (b / NSEC_PER_SEC);
++ r->tv_nsec = a->tv_nsec + (b % NSEC_PER_SEC);
++
++ if (r->tv_nsec >= NSEC_PER_SEC) {
++ r->tv_sec++;
++ r->tv_nsec -= NSEC_PER_SEC;
++ } else if (r->tv_nsec < 0) {
++ r->tv_sec--;
++ r->tv_nsec += NSEC_PER_SEC;
++ }
++}
++
++/* Add a millisecond value to a timespec
++ *
++ * \param r[out] result: a + b
++ * \param a[in] base operand as timespec
++ * \param b[in] operand in milliseconds
++ */
++static inline void
++timespec_add_msec(struct timespec *r, const struct timespec *a, int64_t b)
++{
++ return timespec_add_nsec(r, a, b * 1000000);
++}
++
+ /* Convert timespec to nanoseconds
+ *
+ * \param a timespec
+@@ -60,6 +95,155 @@ timespec_to_nsec(const struct timespec *a)
+ return (int64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
+ }
+
++/* Subtract timespecs and return result in nanoseconds
++ *
++ * \param a[in] operand
++ * \param b[in] operand
++ * \return to_nanoseconds(a - b)
++ */
++static inline int64_t
++timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b)
++{
++ struct timespec r;
++ timespec_sub(&r, a, b);
++ return timespec_to_nsec(&r);
++}
++
++/* Convert timespec to milliseconds
++ *
++ * \param a timespec
++ * \return milliseconds
++ *
++ * Rounding to integer milliseconds happens always down (floor()).
++ */
++static inline int64_t
++timespec_to_msec(const struct timespec *a)
++{
++ return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
++}
++
++/* Subtract timespecs and return result in milliseconds
++ *
++ * \param a[in] operand
++ * \param b[in] operand
++ * \return to_milliseconds(a - b)
++ */
++static inline int64_t
++timespec_sub_to_msec(const struct timespec *a, const struct timespec *b)
++{
++ return timespec_sub_to_nsec(a, b) / 1000000;
++}
++
++/* Convert timespec to microseconds
++ *
++ * \param a timespec
++ * \return microseconds
++ *
++ * Rounding to integer microseconds happens always down (floor()).
++ */
++static inline int64_t
++timespec_to_usec(const struct timespec *a)
++{
++ return (int64_t)a->tv_sec * 1000000 + a->tv_nsec / 1000;
++}
++
++/* Convert timespec to protocol data
++ *
++ * \param a timespec
++ * \param tv_sec_hi[out] the high bytes of the seconds part
++ * \param tv_sec_lo[out] the low bytes of the seconds part
++ * \param tv_nsec[out] the nanoseconds part
++ *
++ * The input timespec must be normalized (the nanoseconds part should
++ * be less than 1 second) and non-negative.
++ */
++static inline void
++timespec_to_proto(const struct timespec *a, uint32_t *tv_sec_hi,
++ uint32_t *tv_sec_lo, uint32_t *tv_nsec)
++{
++ assert(a->tv_sec >= 0);
++ assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC);
++
++ uint64_t sec64 = a->tv_sec;
++
++ *tv_sec_hi = sec64 >> 32;
++ *tv_sec_lo = sec64 & 0xffffffff;
++ *tv_nsec = a->tv_nsec;
++}
++
++/* Convert nanoseconds to timespec
++ *
++ * \param a timespec
++ * \param b nanoseconds
++ */
++static inline void
++timespec_from_nsec(struct timespec *a, int64_t b)
++{
++ a->tv_sec = b / NSEC_PER_SEC;
++ a->tv_nsec = b % NSEC_PER_SEC;
++}
++
++/* Convert microseconds to timespec
++ *
++ * \param a timespec
++ * \param b microseconds
++ */
++static inline void
++timespec_from_usec(struct timespec *a, int64_t b)
++{
++ timespec_from_nsec(a, b * 1000);
++}
++
++/* Convert milliseconds to timespec
++ *
++ * \param a timespec
++ * \param b milliseconds
++ */
++static inline void
++timespec_from_msec(struct timespec *a, int64_t b)
++{
++ timespec_from_nsec(a, b * 1000000);
++}
++
++/* Convert protocol data to timespec
++ *
++ * \param a[out] timespec
++ * \param tv_sec_hi the high bytes of seconds part
++ * \param tv_sec_lo the low bytes of seconds part
++ * \param tv_nsec the nanoseconds part
++ */
++static inline void
++timespec_from_proto(struct timespec *a, uint32_t tv_sec_hi,
++ uint32_t tv_sec_lo, uint32_t tv_nsec)
++{
++ a->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
++ a->tv_nsec = tv_nsec;
++}
++
++/* Check if a timespec is zero
++ *
++ * \param a timespec
++ * \return whether the timespec is zero
++ */
++static inline bool
++timespec_is_zero(const struct timespec *a)
++{
++ return a->tv_sec == 0 && a->tv_nsec == 0;
++}
++
++/* Check if two timespecs are equal
++ *
++ * \param a[in] timespec to check
++ * \param b[in] timespec to check
++ * \return whether timespecs a and b are equal
++ */
++static inline bool
++timespec_eq(const struct timespec *a, const struct timespec *b)
++{
++ return a->tv_sec == b->tv_sec &&
++ a->tv_nsec == b->tv_nsec;
++}
++
+ /* Convert milli-Hertz to nanoseconds
+ *
+ * \param mhz frequency in mHz, not zero
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0007-PATCH-weston-add-mtk-test-client.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0007-PATCH-weston-add-mtk-test-client.patch
new file mode 100644
index 0000000..2eada19
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0007-PATCH-weston-add-mtk-test-client.patch
@@ -0,0 +1,1308 @@
+From 62628502047672c190fadc3f98caf427df25dfe6 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 14:31:26 +0800
+Subject: [PATCH 7/8] [PATCH] weston: add mtk test client
+
+add mtk test client
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ Makefile.am | 14 +
+ clients/simple-configure-mtk.c | 1247 ++++++++++++++++++++++++++++++++++++++++
+ configure.ac | 1 +
+ 3 files changed, 1262 insertions(+)
+ create mode 100644 clients/simple-configure-mtk.c
+
+diff --git a/Makefile.am b/Makefile.am
+index a9e48f8..7efa5a0 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -668,6 +668,20 @@ nodist_weston_simple_screenshooter_mtk_SOURCES = \
+ weston_simple_screenshooter_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+ weston_simple_screenshooter_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
+
++if BUILD_SIMPLE_CONFIGURE_MTK_CLIENT
++demo_clients += weston-simple-configure-mtk
++weston_simple_configure_mtk_SOURCES = clients/simple-configure-mtk.c
++nodist_weston_simple_configure_mtk_SOURCES = \
++ protocol/xdg-shell-unstable-v6-protocol.c \
++ protocol/xdg-shell-unstable-v6-client-protocol.h \
++ protocol/fullscreen-shell-unstable-v1-protocol.c \
++ protocol/fullscreen-shell-unstable-v1-client-protocol.h \
++ protocol/linux-dmabuf-unstable-v1-protocol.c \
++ protocol/linux-dmabuf-unstable-v1-client-protocol.h
++weston_simple_configure_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
++weston_simple_configure_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
++BUILT_SOURCES += protocol/linux-dmabuf-unstable-v1-client-protocol.h
++endif
+
+ noinst_LTLIBRARIES += libtoytoolkit.la
+
+diff --git a/clients/simple-configure-mtk.c b/clients/simple-configure-mtk.c
+new file mode 100644
+index 0000000..8b146ff
+--- /dev/null
++++ b/clients/simple-configure-mtk.c
+@@ -0,0 +1,1247 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdbool.h>
++#include <math.h>
++#include <assert.h>
++#include <sys/mman.h>
++#include <signal.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <linux/input.h>
++
++#include <wayland-client.h>
++#include <wayland-cursor.h>
++
++#include <drm_fourcc.h>
++#include <xf86drm.h>
++#include <xf86drmMode.h>
++
++#include <sys/types.h>
++#include <unistd.h>
++
++//#include "ivi-application-client-protocol.h"
++#include "xdg-shell-unstable-v6-client-protocol.h"
++#include "linux-dmabuf-unstable-v1-client-protocol.h"
++#include "fullscreen-shell-unstable-v1-client-protocol.h"
++#include "weston-configure-mtk-client-protocol.h"
++
++#include <shared/platform.h>
++
++//#define IVI_SURFACE_ID 9000
++#define MAX_IMAGE 16
++#define ALIGN(X,bit) ((X + bit-1) & (~(bit-1)))
++#define MAX_DMABUF_PLANES 4
++#define RES_NUM 4
++#define MAX_LEN 60
++
++struct window;
++struct seat;
++
++struct display {
++ struct wl_display *display;
++ struct wl_registry *registry;
++ struct wl_compositor *compositor;
++ struct zxdg_shell_v6 *shell;
++ struct zwp_fullscreen_shell_v1 *fshell;
++ //struct ivi_application *ivi_application;
++ struct wl_seat *seat;
++ struct wl_pointer *pointer;
++ struct wl_touch *touch;
++ struct wl_keyboard *keyboard;
++ struct wl_shm *shm;
++ struct zwp_linux_dmabuf_v1 *dmabuf;
++ struct wl_list output_list; /* struct output_unit::link */
++ struct wl_cursor_theme *cursor_theme;
++ struct wl_cursor *default_cursor;
++ struct wl_surface *cursor_surface;
++ struct window *window;
++ struct config_switch *config_switch;
++};
++
++struct geometry {
++ int width, height;
++};
++
++struct buffer {
++ struct wl_buffer *buffer;
++ void *dma_map;
++ int busy;
++};
++
++struct file_arg{
++ char filename[MAX_LEN];
++ int width;
++ int height;
++ int format;
++};
++
++struct window {
++ struct display *display;
++ struct geometry geometry, window_size;
++ bool wait_for_configure;
++ struct {
++ struct file_arg fProp;
++ struct buffer out_bufs[RES_NUM];
++ } image;
++ struct img_texture *tex;
++ uint32_t benchmark_time, frames;
++ struct wl_surface *surface;
++ struct zxdg_surface_v6 *xdg_surface;
++ struct zxdg_toplevel_v6 *xdg_toplevel;
++ //struct ivi_surface *ivi_surface;
++ struct wl_callback *callback;
++ int fullscreen, opaque, buffer_size, overlay, format;
++ enum wl_output_transform transform;
++ int drm_card_fd;
++ struct config_switch_set *switch_set;
++};
++
++struct img_texture {
++ struct context *ctx;
++
++ /* input */
++ int width;
++ int height;
++ int drm_format;
++ int bpp;
++ int plane_nums;
++
++ int pitch[MAX_DMABUF_PLANES];
++ int offset[MAX_DMABUF_PLANES];
++ int fds[MAX_DMABUF_PLANES];
++ int handle[MAX_DMABUF_PLANES];
++
++ void *texbuf;
++ int size;
++};
++
++typedef enum _IMG_FORMAT_E {
++ IMG_FORMAT_RGB565 = 0,
++ IMG_FORMAT_XRGB8888,
++ IMG_FORMAT_ARGB8888,
++ IMG_FORMAT_YUYV,
++ IMG_FORMAT_NV12,
++ IMG_FORMAT_NV16,
++ IMG_FORMAT_YUV420,
++ IMG_FORMAT_YVU420,
++ IMG_FORMAT_LAST,
++} IMG_FORMAT_T;
++
++struct drm_fourcc_info {
++ unsigned int drm_format;
++ int plane_cnt;
++ int bpp;
++};
++
++static struct drm_fourcc_info fourcc_tbl[] = {
++ {DRM_FORMAT_RGB565, 1, 16},
++ {DRM_FORMAT_RGBA5551, 1, 16},
++ {DRM_FORMAT_RGBA4444, 1, 16},
++ {DRM_FORMAT_XRGB8888, 1, 32},
++ {DRM_FORMAT_XBGR8888, 1, 32},
++ {DRM_FORMAT_RGBX8888, 1, 32},
++ {DRM_FORMAT_BGRX8888, 1, 32},
++ {DRM_FORMAT_ARGB8888, 1, 32},
++ {DRM_FORMAT_ABGR8888, 1, 32},
++ {DRM_FORMAT_RGBA8888, 1, 32},
++ {DRM_FORMAT_BGRA8888, 1, 32},
++ {DRM_FORMAT_YUYV, 1, 16},
++ {DRM_FORMAT_VYUY, 1, 16},
++ {DRM_FORMAT_NV12, 2, 12},
++ {DRM_FORMAT_NV21, 2, 12},
++ {DRM_FORMAT_NV16, 2, 16},
++ {DRM_FORMAT_NV61, 2, 16},
++ {DRM_FORMAT_YUV420, 3, 12},
++ {DRM_FORMAT_YVU420, 3, 12},
++ {0, 0, 0},
++};
++
++static int running = 1;
++static int debug = 0;
++
++static void
++redraw(void *data, struct wl_callback *callback, uint32_t time);
++
++static int _format_transfer(int format, int *drm_format)
++{
++ int new_format;
++
++ if (!drm_format)
++ return -1;
++
++ switch (format) {
++ case IMG_FORMAT_RGB565:
++ new_format = DRM_FORMAT_RGB565;
++ break;
++ case IMG_FORMAT_XRGB8888:
++ new_format = DRM_FORMAT_XRGB8888;
++ break;
++ case IMG_FORMAT_ARGB8888:
++ new_format = DRM_FORMAT_ARGB8888;
++ break;
++ case IMG_FORMAT_YUYV:
++ new_format = DRM_FORMAT_YUYV;
++ break;
++ case IMG_FORMAT_NV12:
++ new_format = DRM_FORMAT_NV12;
++ break;
++ case IMG_FORMAT_NV16:
++ new_format = DRM_FORMAT_NV16;
++ break;
++ case IMG_FORMAT_YUV420:
++ new_format = DRM_FORMAT_YUV420;
++ break;
++ case IMG_FORMAT_YVU420:
++ new_format = DRM_FORMAT_YVU420;
++ break;
++ default:
++ return -2;
++ }
++ *drm_format = new_format;
++
++ return 0;
++}
++
++static struct drm_fourcc_info *
++get_drm_format_info(unsigned int format)
++{
++ int i;
++
++ for (i = 0; ; i++) {
++ if ( format == fourcc_tbl[i].drm_format){
++ return &fourcc_tbl[i];
++ }
++ if ( fourcc_tbl[i].drm_format == 0)
++ break;
++ }
++ return NULL;
++}
++
++static char *
++_get_tex_resource(int drifd, struct img_texture *tex)
++{
++ void *map = NULL;
++ struct drm_mode_create_dumb create_arg;
++ struct drm_mode_map_dumb map_arg;
++ struct drm_prime_handle prime_arg;
++ struct drm_fourcc_info *format_info;
++ int i, ret;
++ unsigned int alloc_size;
++
++ memset(&create_arg, 0, sizeof(create_arg));
++ memset(&map_arg, 0, sizeof(map_arg));
++ memset(&prime_arg, 0, sizeof(prime_arg));
++
++ for(i = 0; i < MAX_DMABUF_PLANES; i ++ )
++ tex->fds[i] = -1;
++
++ format_info = get_drm_format_info(tex->drm_format);
++ if (format_info == NULL)
++ return NULL;
++
++ tex->bpp = format_info->bpp;
++ if (format_info->plane_cnt == 3) {
++ if (format_info->bpp == 12) {
++ tex->pitch[0] = ALIGN(tex->width, 16);
++ tex->pitch[1] = tex->pitch[0] / 2;
++ tex->pitch[2] = tex->pitch[0] / 2;
++ tex->offset[0] = 0;
++ tex->offset[1] = tex->pitch[0] * tex->height;
++ tex->offset[2] = tex->offset[1] + tex->pitch[1] * tex->height / 2;
++ alloc_size = tex->offset[2] + tex->pitch[2] * tex->height / 2;
++ } else {
++ fprintf(stderr,"debug: please add new format 0x%x\n", tex->drm_format);
++ return NULL;
++ }
++ } else if (format_info->plane_cnt == 2) {
++ tex->pitch[0] = ALIGN(tex->width, 16);
++ tex->offset[0] = 0;
++ if (format_info->bpp == 16) {
++ tex->pitch[1] = tex->pitch[0];
++ tex->offset[1] = tex->pitch[0] * tex->height;
++ alloc_size = tex->offset[1] + tex->pitch[1] * tex->height;
++ fprintf(stderr,"debug: %s %d alloc_size = %d o/p [%d %d]\n",
++ __FUNCTION__, __LINE__, alloc_size, tex->offset[1], tex->pitch[1]);
++ }
++ else if (format_info->bpp == 12) {
++ tex->pitch[1] = tex->pitch[0] / 2;
++ tex->offset[1] = tex->pitch[0] * tex->height;
++ alloc_size = tex->offset[1] + tex->pitch[1] * tex->height;
++ } else {
++ fprintf(stderr,"debug: please add new format 0x%x\n", tex->drm_format);
++ return NULL;
++ }
++ } else {
++ tex->pitch[0] = ALIGN(tex->width * tex->bpp / 8, 16);
++ tex->offset[0] = 0;
++ alloc_size = tex->pitch[0] * tex->height;
++ }
++
++ create_arg.bpp = 8;
++ create_arg.width = alloc_size;
++ create_arg.height = 1;
++
++ ret = drmIoctl(drifd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
++ if (ret) {
++ fprintf(stderr,"error: drmIoctl %d DRM_IOCTL_MODE_CREATE_DUMB fail %d\n", drifd, ret);
++ return NULL;
++ }
++
++ map_arg.handle = create_arg.handle;
++
++ ret = drmIoctl(drifd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
++ if (ret) {
++ fprintf(stderr,"error: drmIoctl DRM_IOCTL_MODE_MAP_DUMB fail %d\n", ret);
++ return NULL;
++ }
++
++ map = mmap(0, create_arg.size, PROT_WRITE|PROT_READ , MAP_SHARED, drifd, map_arg.offset);
++ if (map == MAP_FAILED) {
++ fprintf(stderr,"error: mmap fail : %p\n", map);
++ return NULL;
++ }
++
++ prime_arg.handle = create_arg.handle;
++ prime_arg.flags = DRM_CLOEXEC;
++ ret = drmIoctl(drifd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_arg);
++ if (ret || prime_arg.fd == -1) {
++ fprintf(stderr,"error: drmIoctl DRM_IOCTL_PRIME_HANDLE_TO_FD fail %d fd=%d\n",ret,prime_arg.fd);
++ return NULL;
++ }
++
++ for (i = 0; i < format_info->plane_cnt; i++) {
++ tex->fds[i] = prime_arg.fd;
++ tex->handle[i] = create_arg.handle;
++ }
++ tex->plane_nums = format_info->plane_cnt;
++ tex->texbuf = map;
++ tex->size = create_arg.size;
++
++ return map;
++}
++
++static int
++init_img_texture(struct window *window)
++{
++ int ret;
++ struct img_texture *tex;
++ tex = malloc(sizeof *tex);
++ if (tex == NULL)
++ return -1;
++
++ ret = _format_transfer(window->image.fProp.format, &(tex->drm_format));
++ if (ret < 0)
++ return -1;
++
++ tex->width = window->image.fProp.width;
++ tex->height= window->image.fProp.height;
++
++ window->tex = tex;
++ return 0;
++}
++
++static void
++buffer_release(void *data, struct wl_buffer *buffer)
++{
++ struct buffer *mybuf = data;
++
++ mybuf->busy = 0;
++}
++
++static const struct wl_buffer_listener buffer_listener = {
++ buffer_release
++};
++
++static void
++create_succeeded(void *data,
++ struct zwp_linux_buffer_params_v1 *params,
++ struct wl_buffer *new_buffer)
++{
++ struct buffer *buffer = data;
++
++ buffer->buffer = new_buffer;
++ wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
++
++ zwp_linux_buffer_params_v1_destroy(params);
++}
++
++static void
++create_failed(void *data, struct zwp_linux_buffer_params_v1 *params)
++{
++ struct buffer *buffer = data;
++
++ buffer->buffer = NULL;
++
++ zwp_linux_buffer_params_v1_destroy(params);
++
++ running = false;
++
++ fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
++}
++
++static const struct zwp_linux_buffer_params_v1_listener params_listener = {
++ create_succeeded,
++ create_failed
++};
++
++static int
++create_dmabuf_buffer(struct display *display, struct buffer *buffer)
++{
++ struct zwp_linux_buffer_params_v1 *params;
++ struct img_texture *cbtex = display->window->tex;
++ uint64_t modifier;
++ uint32_t flags;
++ int i;
++ /* output */
++ buffer->dma_map = _get_tex_resource(display->window->drm_card_fd, cbtex);
++
++ if (buffer->dma_map == NULL) {
++ fprintf(stderr, "error: _get_tex_resource failed\n");
++ return -1;
++ }
++
++ modifier = 0;
++ params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
++
++ for(i = 0; i < cbtex->plane_nums; i ++)
++ {
++ zwp_linux_buffer_params_v1_add(params,
++ cbtex->fds[i],
++ i, /* plane_idx */
++ cbtex->offset[i],/* offset */
++ cbtex->pitch[i],
++ modifier >> 32,
++ modifier & 0xffffffff);
++ }
++ zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, buffer);
++ zwp_linux_buffer_params_v1_create(params,
++ cbtex->width,
++ cbtex->height,
++ cbtex->drm_format,
++ flags);
++
++ /* params is destroyed by the event handlers */
++ wl_display_roundtrip(display->display);
++ if (buffer->buffer == NULL) {
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++_load_file(void *buf, int len, const char *file_name)
++{
++ int ret, nread = 0;
++
++ FILE *fp = fopen(file_name, "rb");
++ if (!fp)
++ {
++ fprintf(stderr,"debug: file %s open failed\n", file_name);
++ return -1;
++ }
++
++ while (nread < len) {
++ ret = fread(buf + nread, 1, len - nread, fp);
++ if (!ret)
++ break;
++ nread += ret;
++ }
++
++ fclose(fp);
++ return 0;
++}
++
++static int
++_kms_device_fd(void)
++{
++ int i;
++ bool has_conn = false;
++ for (i = 0; i < 8; ++i) {
++ char path[99];
++ sprintf(path, "/dev/dri/card%d", i);
++ fprintf(stderr, "debug: trying %s\n", path);
++ int fd = open(path, O_RDWR | O_CLOEXEC);
++ if (fd >= 0) {
++ drmModeResPtr mr = drmModeGetResources(fd);
++ if (mr) {
++ has_conn = mr->count_connectors > 0;
++ drmModeFreeResources(mr);
++ }
++ if (has_conn) {
++ fprintf(stderr, "debug: using %s\n", path);
++ return fd;
++ }
++ close(fd);
++ }
++ }
++ return -1;
++}
++
++static void
++handle_xdg_surface_configure(void *data, struct zxdg_surface_v6 *surface,
++ uint32_t serial)
++{
++ struct window *window = data;
++ fprintf(stderr, "handle_xdg_surface_configure\n");
++
++ zxdg_surface_v6_ack_configure(surface, serial);
++
++ if (window->wait_for_configure) {
++ redraw(window, NULL, 0);
++ window->wait_for_configure = false;
++ }
++}
++
++static const struct zxdg_surface_v6_listener xdg_surface_listener = {
++ handle_xdg_surface_configure,
++};
++
++
++static void
++handle_toplevel_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
++ int32_t width, int32_t height,
++ struct wl_array *states)
++{
++ struct window *window = data;
++ uint32_t *p;
++
++ window->fullscreen = 0;
++ wl_array_for_each(p, states) {
++ uint32_t state = *p;
++ switch (state) {
++ case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
++ window->fullscreen = 1;
++ break;
++ }
++ }
++
++ if (width > 0 && height > 0) {
++ if (!window->fullscreen) {
++ window->window_size.width = width;
++ window->window_size.height = height;
++ }
++ window->geometry.width = width;
++ window->geometry.height = height;
++ } else if (!window->fullscreen) {
++ window->geometry = window->window_size;
++ }
++
++ /*if (window->native)
++ wl_egl_window_resize(window->native,
++ window->geometry.width,
++ window->geometry.height, 0, 0);*/
++}
++
++static void
++handle_toplevel_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
++{
++ running = 0;
++}
++
++static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
++ handle_toplevel_configure,
++ handle_toplevel_close,
++};
++/*
++static void
++handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface,
++ int32_t width, int32_t height)
++{
++
++}
++
++static const struct ivi_surface_listener ivi_surface_listener = {
++ handle_ivi_surface_configure,
++};
++*/
++static struct buffer *
++window_next_buffer(struct window *window)
++{
++ struct buffer *buffer = NULL;
++ int i, ret = 0;
++
++ for(i = 0; i < RES_NUM; i++) {
++ if (!window->image.out_bufs[i].busy) {
++ buffer = &window->image.out_bufs[i];
++ break;
++ }
++ }
++
++ if (!buffer)
++ return NULL;
++
++ if (!buffer->buffer) {
++ ret = create_dmabuf_buffer(window->display, buffer);
++ if (ret < 0)
++ return NULL;
++ if(i%2)
++ _load_file(buffer->dma_map, window->tex->size, window->image.fProp.filename);
++ else
++ memset(buffer->dma_map, 0, window->tex->size);
++ }
++
++ return buffer;
++}
++
++static void
++create_surface(struct window *window)
++{
++ struct display *display = window->display;
++
++ window->surface = wl_compositor_create_surface(display->compositor);
++ display->cursor_surface =
++ wl_compositor_create_surface(display->compositor);
++
++ window->switch_set = config_switch_connect(display->config_switch, window->surface);
++
++ if (display->shell) {
++ window->xdg_surface =
++ zxdg_shell_v6_get_xdg_surface(display->shell,
++ window->surface);
++
++ assert(window->xdg_surface);
++
++ zxdg_surface_v6_add_listener(window->xdg_surface,
++ &xdg_surface_listener, window);
++
++ window->xdg_toplevel =
++ zxdg_surface_v6_get_toplevel(window->xdg_surface);
++ zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
++ &xdg_toplevel_listener, window);
++
++ zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-configure-mtk");
++ window->wait_for_configure = true;
++ wl_surface_commit(window->surface);
++ } else if (display->fshell) {
++ zwp_fullscreen_shell_v1_present_surface(display->fshell,
++ window->surface,
++ ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
++ NULL);
++ //} else if (display->ivi_application ) {
++ // uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
++ // window->ivi_surface =
++ // ivi_application_surface_create(display->ivi_application,
++ // id_ivisurf, window->surface);
++ // if (window->ivi_surface == NULL) {
++ // fprintf(stderr, "Failed to create ivi_client_surface\n");
++ // abort();
++ // }
++//
++ // ivi_surface_add_listener(window->ivi_surface,
++ // &ivi_surface_listener, window);
++
++ } else {
++ assert(0);
++ }
++
++}
++
++static void
++destroy_surface(struct window *window)
++{
++ if (window->xdg_toplevel)
++ zxdg_toplevel_v6_destroy(window->xdg_toplevel);
++ if (window->xdg_surface)
++ zxdg_surface_v6_destroy(window->xdg_surface);
++ //if (window->display->ivi_application)
++ // ivi_surface_destroy(window->ivi_surface);
++ if (window->display->fshell)
++ zwp_fullscreen_shell_v1_release(window->display->fshell);
++ wl_surface_destroy(window->surface);
++
++ if (window->callback)
++ wl_callback_destroy(window->callback);
++
++ if (window->image.out_bufs[0].buffer)
++ wl_buffer_destroy(window->image.out_bufs[0].buffer);
++ if (window->image.out_bufs[1].buffer)
++ wl_buffer_destroy(window->image.out_bufs[1].buffer);
++ if (window->image.out_bufs[2].buffer)
++ wl_buffer_destroy(window->image.out_bufs[2].buffer);
++}
++
++static const struct wl_callback_listener frame_listener;
++
++static void
++redraw(void *data, struct wl_callback *callback, uint32_t time)
++{
++ struct window *window = data;
++ struct buffer *buffer;
++ char filename[MAX_LEN] = {0};
++ static const uint32_t benchmark_interval = 5;
++ struct wl_region *region;
++ struct timeval tv;
++ int tmp;
++
++ buffer = window_next_buffer(window);
++ if (!buffer) {
++ fprintf(stderr,
++ !callback ? "error: Failed to create the first buffer.\n" :
++ "error: Both buffers busy at redraw(). Server bug?\n");
++ abort();
++ }
++
++ gettimeofday(&tv, NULL);
++ time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
++ if (window->frames == 0)
++ window->benchmark_time = time;
++ if (time - window->benchmark_time > (benchmark_interval * 1000)) {
++ printf("debug: %d frames in %d seconds: %f fps\n",
++ window->frames,
++ benchmark_interval,
++ (float) window->frames / benchmark_interval);
++ window->benchmark_time = time;
++ window->frames = 0;
++ }
++
++ if (window->opaque || window->fullscreen) {
++ region = wl_compositor_create_region(window->display->compositor);
++ wl_region_add(region, 0, 0,
++ window->geometry.width,
++ window->geometry.height);
++ wl_surface_set_opaque_region(window->surface, region);
++ wl_region_destroy(region);
++ } else {
++ wl_surface_set_opaque_region(window->surface, NULL);
++ }
++
++ wl_surface_attach(window->surface, buffer->buffer, 0, 0);
++ wl_surface_set_buffer_transform(window->surface,
++ window->transform);
++ wl_surface_damage(window->surface,
++ 0, 0, window->geometry.width, window->geometry.height);
++
++ if (callback)
++ wl_callback_destroy(callback);
++
++ window->callback = wl_surface_frame(window->surface);
++ wl_callback_add_listener(window->callback, &frame_listener, window);
++ wl_surface_commit(window->surface);
++ buffer->busy = 1;
++
++ window->frames++;
++}
++
++static const struct wl_callback_listener frame_listener = {
++ redraw
++};
++
++static void
++pointer_handle_enter(void *data, struct wl_pointer *pointer,
++ uint32_t serial, struct wl_surface *surface,
++ wl_fixed_t sx, wl_fixed_t sy)
++{
++ struct display *display = data;
++ struct wl_buffer *buffer;
++ struct wl_cursor *cursor = display->default_cursor;
++ struct wl_cursor_image *image;
++
++ if (display->window->fullscreen)
++ wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
++ else if (cursor) {
++ image = display->default_cursor->images[0];
++ buffer = wl_cursor_image_get_buffer(image);
++ if (!buffer)
++ return;
++ wl_pointer_set_cursor(pointer, serial,
++ display->cursor_surface,
++ image->hotspot_x,
++ image->hotspot_y);
++ wl_surface_attach(display->cursor_surface, buffer, 0, 0);
++ wl_surface_damage(display->cursor_surface, 0, 0,
++ image->width, image->height);
++ wl_surface_commit(display->cursor_surface);
++ }
++
++}
++
++static void
++pointer_handle_leave(void *data, struct wl_pointer *pointer,
++ uint32_t serial, struct wl_surface *surface)
++{
++}
++
++static void
++pointer_handle_motion(void *data, struct wl_pointer *pointer,
++ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
++{
++
++}
++
++static void
++pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
++ uint32_t serial, uint32_t time, uint32_t button,
++ uint32_t state)
++{
++ struct display *display = data;
++
++ if (!display->window->xdg_surface)
++ return;
++
++ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
++ zxdg_toplevel_v6_move(display->window->xdg_toplevel,
++ display->seat, serial);
++}
++
++static void
++pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
++ uint32_t time, uint32_t axis, wl_fixed_t value)
++{
++}
++
++static const struct wl_pointer_listener pointer_listener = {
++ pointer_handle_enter,
++ pointer_handle_leave,
++ pointer_handle_motion,
++ pointer_handle_button,
++ pointer_handle_axis,
++};
++
++static void
++touch_handle_down(void *data, struct wl_touch *wl_touch,
++ uint32_t serial, uint32_t time, struct wl_surface *surface,
++ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
++{
++ struct display *d = (struct display *)data;
++
++ if (!d->shell)
++ return;
++
++ zxdg_toplevel_v6_move(d->window->xdg_toplevel, d->seat, serial);
++}
++
++static void
++touch_handle_up(void *data, struct wl_touch *wl_touch,
++ uint32_t serial, uint32_t time, int32_t id)
++{
++}
++
++static void
++touch_handle_motion(void *data, struct wl_touch *wl_touch,
++ uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
++{
++}
++
++static void
++touch_handle_frame(void *data, struct wl_touch *wl_touch)
++{
++}
++
++static void
++touch_handle_cancel(void *data, struct wl_touch *wl_touch)
++{
++}
++
++static const struct wl_touch_listener touch_listener = {
++ touch_handle_down,
++ touch_handle_up,
++ touch_handle_motion,
++ touch_handle_frame,
++ touch_handle_cancel,
++};
++
++static void
++keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
++ uint32_t format, int fd, uint32_t size)
++{
++}
++
++static void
++keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, struct wl_surface *surface,
++ struct wl_array *keys)
++{
++}
++
++static void
++keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, struct wl_surface *surface)
++{
++}
++
++static void
++keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, uint32_t time, uint32_t key,
++ uint32_t state)
++{
++ struct display *d = data;
++
++ if (!d->shell)
++ return;
++
++ if (key == KEY_F11 && state) {
++ if (d->window->fullscreen)
++ zxdg_toplevel_v6_unset_fullscreen(d->window->xdg_toplevel);
++ else
++ zxdg_toplevel_v6_set_fullscreen(d->window->xdg_toplevel, NULL);
++ } else if (key == KEY_ESC && state)
++ running = 0;
++}
++
++static void
++keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, uint32_t mods_depressed,
++ uint32_t mods_latched, uint32_t mods_locked,
++ uint32_t group)
++{
++}
++
++static const struct wl_keyboard_listener keyboard_listener = {
++ keyboard_handle_keymap,
++ keyboard_handle_enter,
++ keyboard_handle_leave,
++ keyboard_handle_key,
++ keyboard_handle_modifiers,
++};
++
++static void
++seat_handle_capabilities(void *data, struct wl_seat *seat,
++ enum wl_seat_capability caps)
++{
++ struct display *d = data;
++
++ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
++ d->pointer = wl_seat_get_pointer(seat);
++ wl_pointer_add_listener(d->pointer, &pointer_listener, d);
++ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
++ wl_pointer_destroy(d->pointer);
++ d->pointer = NULL;
++ }
++
++ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
++ d->keyboard = wl_seat_get_keyboard(seat);
++ wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
++ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) {
++ wl_keyboard_destroy(d->keyboard);
++ d->keyboard = NULL;
++ }
++
++ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !d->touch) {
++ d->touch = wl_seat_get_touch(seat);
++ wl_touch_set_user_data(d->touch, d);
++ wl_touch_add_listener(d->touch, &touch_listener, d);
++ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && d->touch) {
++ wl_touch_destroy(d->touch);
++ d->touch = NULL;
++ }
++}
++
++static const struct wl_seat_listener seat_listener = {
++ seat_handle_capabilities,
++};
++
++
++static void
++xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
++{
++ zxdg_shell_v6_pong(shell, serial);
++}
++
++static const struct zxdg_shell_v6_listener xdg_shell_listener = {
++ xdg_shell_ping,
++};
++
++static void
++dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format)
++{
++ fprintf(stderr, "debug: Support drm_format 0x%x \n", format);
++}
++
++static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
++ dmabuf_format
++};
++
++static void
++registry_handle_global(void *data, struct wl_registry *registry,
++ uint32_t name, const char *interface, uint32_t version)
++{
++ struct display *d = data;
++
++ if (strcmp(interface, "wl_compositor") == 0) {
++ d->compositor =
++ wl_registry_bind(registry, name,
++ &wl_compositor_interface, 2);
++ } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
++ d->shell = wl_registry_bind(registry, name,
++ &zxdg_shell_v6_interface, 1);
++ zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
++ } else if (strcmp(interface, "wl_seat") == 0) {
++ d->seat = wl_registry_bind(registry, name,
++ &wl_seat_interface, 1);
++ wl_seat_add_listener(d->seat, &seat_listener, d);
++ } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
++ d->fshell = wl_registry_bind(registry, name,
++ &zwp_fullscreen_shell_v1_interface, 1);
++ } else if (strcmp(interface, "wl_shm") == 0) {
++ d->shm = wl_registry_bind(registry, name,
++ &wl_shm_interface, 1);
++ d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
++ if (!d->cursor_theme) {
++ fprintf(stderr, "unable to load default theme\n");
++ return;
++ }
++ d->default_cursor =
++ wl_cursor_theme_get_cursor(d->cursor_theme, "grabbing");
++ if (!d->default_cursor) {
++ fprintf(stderr, "unable to load default grabbing pointer\n");
++ // TODO: abort ?
++ }
++ //} else if (strcmp(interface, "ivi_application") == 0) {
++ // d->ivi_application =
++ // wl_registry_bind(registry, name,
++ // &ivi_application_interface, 1);
++ } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
++ d->dmabuf = wl_registry_bind(registry, name,
++ &zwp_linux_dmabuf_v1_interface, 1);
++ zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
++ } else if (strcmp(interface, "config_switch") == 0) {
++ d->config_switch =
++ wl_registry_bind(registry, name,
++ &config_switch_interface, 1);
++ }
++}
++
++static void
++registry_handle_global_remove(void *data, struct wl_registry *registry,
++ uint32_t name)
++{
++}
++
++static const struct wl_registry_listener registry_listener = {
++ registry_handle_global,
++ registry_handle_global_remove
++};
++
++static void
++destroy_display(struct display *display)
++{
++ if (display->dmabuf)
++ zwp_linux_dmabuf_v1_destroy(display->dmabuf);
++
++ if (display->shell)
++ zxdg_shell_v6_destroy(display->shell);
++
++ if (display->fshell)
++ zwp_fullscreen_shell_v1_release(display->fshell);
++
++ if (display->compositor)
++ wl_compositor_destroy(display->compositor);
++
++ wl_surface_destroy(display->cursor_surface);
++ if (display->cursor_theme)
++ wl_cursor_theme_destroy(display->cursor_theme);
++
++ //if (display->ivi_application)
++ // ivi_application_destroy(display->ivi_application);
++
++ wl_registry_destroy(display->registry);
++ wl_display_flush(display->display);
++ wl_display_disconnect(display->display);
++ free(display);
++}
++
++static struct display *
++create_display(struct window *window)
++{
++ struct display *display;
++
++ display = malloc(sizeof *display);
++ if (display == NULL) {
++ fprintf(stderr, "out of memory\n");
++ exit(1);
++ }
++ display->display = wl_display_connect(NULL);
++ assert(display->display);
++ display->window = window;
++
++ display->registry = wl_display_get_registry(display->display);
++ wl_registry_add_listener(display->registry,
++ ®istry_listener, display);
++ wl_display_roundtrip(display->display);
++ if (display->dmabuf == NULL) {
++ fprintf(stderr, "No zwp_linux_dmabuf_v1 global found\n");
++ exit(1);
++ }
++ wl_display_roundtrip(display->display);
++
++ return display;
++}
++
++static void
++signal_int(int signum)
++{
++ running = 0;
++}
++
++/*
++ * parse the message inputed for rawdata
++ * egg: -F /usr/share/weston/rawdata.nv16:720x480@5
++ * filename:widthxheight@format
++*/
++static int parse_file(struct file_arg *file, char *p)
++{
++ char *end;
++ char *pPos = p;
++ int len, i;
++
++ len = strlen(pPos) + 1;
++ for (i = 0; i < len; i++)
++ if(pPos[i] == ':')
++ pPos[i] = '\0';
++
++ memcpy(file->filename, pPos, strlen(pPos) + 1);
++ pPos = pPos + strlen(pPos) + 1;
++ file->width = strtoul(pPos, &end, 10);
++ if (*end != 'x')
++ return -EINVAL;
++ pPos = end + 1;
++ file->height = strtoul(pPos, &end, 10);
++ if (*end != '@')
++ return -EINVAL;
++ pPos = end + 1;
++ file->format = strtoul(pPos, &end, 10);
++ if (*end != '\0')
++ return -EINVAL;
++ return 0;
++}
++
++static void init_window(struct window *window)
++{
++ window->geometry.width = 0;
++ window->geometry.height = 0;
++ window->buffer_size = 32;
++ window->transform = WL_OUTPUT_TRANSFORM_NORMAL;
++ window->opaque = 1;
++ window->overlay = 0;
++ window->format = 0;
++ window->drm_card_fd = -1;
++}
++
++static void
++usage(int error_code)
++{
++ fprintf(stderr, "Usage: mtkdraw-dma [OPTIONS]\n\n"
++ " -f Run in fullscreen mode(only desktop-shell valid)\n"
++ " -o Create an opaque surface\n"
++ " -s Use a 16 bpp EGL config\n"
++ " -t Set display buffer transform(0~7)\n"
++ " -F rawdata message(rawdata size provided is 320x480)\n"
++ " eg:-F /usr/share/weston/rawdata.nv16:320x480@5\n"
++ " @14 stand for nv16 format, formats supported as follows\n"
++ " now only support 8 formats\n"
++ " 0 --> IMG_FORMAT_RGB565\n"
++ " 1 --> IMG_FORMAT_XRGB8888\n"
++ " 2 --> IMG_FORMAT_ARGB8888\n"
++ " 3 --> IMG_FORMAT_YUYV\n"
++ " 4 --> IMG_FORMAT_NV12\n"
++ " 5 --> IMG_FORMAT_NV16\n"
++ " 6 --> IMG_FORMAT_YUV420\n"
++ " 7 --> IMG_FORMAT_YVU420\n"
++ " -d Enable debug output\n"
++ " -overlay Enable overlay switch\n"
++ " -h This help text\n\n");
++
++ exit(error_code);
++}
++
++int
++main(int argc, char **argv)
++{
++ struct sigaction sigint;
++ struct display *display;
++ struct window window = { 0 };
++ int i, ret = 0;
++ struct file_arg *file;
++
++ init_window(&window);
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp("-f", argv[i]) == 0)
++ window.fullscreen = 1;
++ else if (strcmp("-o", argv[i]) == 0)
++ window.opaque = 0;
++ else if (strcmp("-s", argv[i]) == 0)
++ window.buffer_size = 16;
++ else if (strcmp("-t", argv[i]) == 0)
++ window.transform = atoi(argv[++i]);
++ else if (strcmp("-F", argv[i]) == 0){
++ ret = parse_file(&window.image.fProp, argv[++i]);
++ if (ret < 0)
++ fprintf(stderr, "error: input error, like: -F "
++ "/usr/share/weston/rawdata.nv16:320x480@5\n");
++ }
++ else if (strcmp("-d", argv[i]) == 0)
++ debug = 1;
++ else if (strcmp("-overlay", argv[i]) == 0)
++ window.overlay = 1;
++ else if (strcmp("-h", argv[i]) == 0)
++ usage(EXIT_SUCCESS);
++ else
++ usage(EXIT_FAILURE);
++ }
++
++ file = &window.image.fProp;
++ if((file->width == 0) || (file->height ==0) || (file->filename == 0))
++ {
++ /*default sample*/
++ file->width = 320;
++ file->height = 480;
++ file->format = IMG_FORMAT_NV16;
++ snprintf(file->filename, MAX_LEN, "/usr/share/weston/rawdata.nv16");
++ fprintf(stderr, "debug: You have choose the default example!\n");
++ }
++
++ fprintf(stderr, "debug: The file is %s width/height/format[%d %d %d]\n",
++ file->filename, file->width, file->height, file->format);
++
++ window.geometry.width = file->width;
++ window.geometry.height = file->height;
++ window.window_size = window.geometry;
++
++ display = create_display(&window);
++ window.display = display;
++ //display->window = &window;
++
++ create_surface(&window);
++
++ ret = init_img_texture(&window);
++ if (ret < 0){
++ fprintf(stderr, "error: init_img_texture failed\n");
++ return -1;
++ }
++
++ window.drm_card_fd = _kms_device_fd();
++ if (window.drm_card_fd < 0) {
++ fprintf(stderr, "error: fail to get drm_card_fd !\n");
++ return -1;
++ }
++ /*
++ * setting sprite_switch = 0, indicate not walk overlay
++ * setting sprite_switch = 1, indicate walk overlay
++ */
++ if(window.overlay)
++ config_switch_set_sprite_switch(window.switch_set, 1);
++ else
++ config_switch_set_sprite_switch(window.switch_set, 0);
++
++ sigint.sa_handler = signal_int;
++ sigemptyset(&sigint.sa_mask);
++ sigint.sa_flags = SA_RESETHAND;
++ sigaction(SIGINT, &sigint, NULL);
++
++ if (!window.wait_for_configure)
++ redraw(&window, NULL, 0);
++
++ while (running && ret != -1)
++ ret = wl_display_dispatch(display->display);
++
++ fprintf(stderr, "debug: simple-configure-mtk exiting\n");
++ destroy_surface(&window);
++ destroy_display(display);
++
++ return 0;
++}
++
++
+diff --git a/configure.ac b/configure.ac
+index 96acf75..e91261d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -440,6 +440,7 @@ if ! test "x$enable_simple_dmabuf_v4l_client" = "xno"; then
+ enable_simple_dmabuf_v4l_client="$have_simple_dmabuf_v4l_client"
+ fi
+ AM_CONDITIONAL(BUILD_SIMPLE_DMABUF_V4L_CLIENT, test "x$enable_simple_dmabuf_v4l_client" = "xyes")
++AM_CONDITIONAL(BUILD_SIMPLE_CONFIGURE_MTK_CLIENT, test "x$enable_simple_dmabuf_v4l_client" = "xyes")
+
+ AC_ARG_ENABLE(clients, [ --enable-clients],, enable_clients=yes)
+ AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0007-weston-screen-shot-add-screen-shot.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0007-weston-screen-shot-add-screen-shot.patch
new file mode 100644
index 0000000..5703148
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0007-weston-screen-shot-add-screen-shot.patch
@@ -0,0 +1,785 @@
+From ae382bde54d71d2b9fdd0228ef084c8fc710eae7 Mon Sep 17 00:00:00 2001
+From: mtk13576 <yr.yang@mediatek.com>
+Date: Thu, 26 Apr 2018 00:23:55 +0800
+Subject: [PATCH 7/9] weston-screen-shot: add screen shot
+
+add screen shot
+Test: ok
+
+Change-Id: I8b724efa64b2b7d542ed8c7c2525ca5c37cf9cc0
+Signed-off-by: mtk13576 <yr.yang@mediatek.com>
+CR-Id: AUTO00016576
+---
+ Makefile.am | 24 +++-
+ clients/simple-screenshooter-mtk.c | 259 +++++++++++++++++++++++++++++++++++
+ libweston/compositor-drm.c | 115 ++++++++++++++++
+ libweston/compositor.c | 3 +
+ libweston/compositor.h | 3 +
+ libweston/pixel-formats.c | 2 +
+ libweston/weston-screenshooter-mtk.c | 129 +++++++++++++++++
+ protocol/weston-configure-mtk.xml | 37 +++++
+ 8 files changed, 569 insertions(+), 3 deletions(-)
+ create mode 100644 clients/simple-screenshooter-mtk.c
+ create mode 100644 libweston/weston-screenshooter-mtk.c
+ create mode 100644 protocol/weston-configure-mtk.xml
+
+diff --git a/Makefile.am b/Makefile.am
+index 238cd2f..e450b95 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -107,6 +107,7 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ libweston/linux-dmabuf.h \
+ libweston/pixel-formats.c \
+ libweston/pixel-formats.h \
++ libweston/weston-screenshooter-mtk.c \
+ shared/helpers.h \
+ shared/matrix.c \
+ shared/matrix.h \
+@@ -180,7 +181,9 @@ nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ protocol/relative-pointer-unstable-v1-protocol.c \
+ protocol/relative-pointer-unstable-v1-server-protocol.h \
+ protocol/pointer-constraints-unstable-v1-protocol.c \
+- protocol/pointer-constraints-unstable-v1-server-protocol.h
++ protocol/pointer-constraints-unstable-v1-server-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-server-protocol.h
+
+ BUILT_SOURCES += $(nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES)
+
+@@ -642,6 +645,18 @@ weston_simple_dmabuf_v4l_LDADD = $(SIMPLE_DMABUF_V4L_CLIENT_LIBS) libshared.la
+ BUILT_SOURCES += protocol/linux-dmabuf-unstable-v1-client-protocol.h
+ endif
+
++demo_clients += weston-simple-screenshooter-mtk
++weston_simple_screenshooter_mtk_SOURCES = clients/simple-screenshooter-mtk.c
++nodist_weston_simple_screenshooter_mtk_SOURCES = \
++ protocol/xdg-shell-unstable-v6-protocol.c \
++ protocol/xdg-shell-unstable-v6-client-protocol.h \
++ protocol/fullscreen-shell-unstable-v1-protocol.c \
++ protocol/fullscreen-shell-unstable-v1-client-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-client-protocol.h
++weston_simple_screenshooter_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
++weston_simple_screenshooter_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
++
+ noinst_LTLIBRARIES += libtoytoolkit.la
+
+ libtoytoolkit_la_SOURCES = \
+@@ -876,7 +891,9 @@ BUILT_SOURCES += \
+ protocol/ivi-hmi-controller-protocol.c \
+ protocol/ivi-hmi-controller-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+- protocol/ivi-application-client-protocol.h
++ protocol/ivi-application-client-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-client-protocol.h
+
+ westondatadir = $(datadir)/weston
+ dist_westondata_DATA = \
+@@ -1509,7 +1526,8 @@ EXTRA_DIST += \
+ protocol/text-cursor-position.xml \
+ protocol/weston-test.xml \
+ protocol/ivi-application.xml \
+- protocol/ivi-hmi-controller.xml
++ protocol/ivi-hmi-controller.xml \
++ protocol/weston-configure-mtk.xml
+
+ #
+ # manual test modules in tests subdirectory
+diff --git a/clients/simple-screenshooter-mtk.c b/clients/simple-screenshooter-mtk.c
+new file mode 100644
+index 0000000..cbca18b
+--- /dev/null
++++ b/clients/simple-screenshooter-mtk.c
+@@ -0,0 +1,259 @@
++/*
++ * Copyright © 2008 Kristian Høgsberg
++ *
++ * 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 <stdint.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <limits.h>
++#include <sys/param.h>
++#include <sys/mman.h>
++#include <cairo.h>
++
++#include <wayland-client.h>
++#include "weston-configure-mtk-client-protocol.h"
++#include "shared/os-compatibility.h"
++#include "shared/xalloc.h"
++
++/* The screenshooter is a good example of a custom object exposed by
++ * the compositor and serves as a test bed for implementing client
++ * side marshalling outside libwayland.so */
++
++static struct wl_shm *shm;
++static struct weston_screenshooter_mtk *mtk_screenshooter;
++static struct wl_list output_list;
++int min_x, min_y, max_x, max_y;
++int buffer_copy_done;
++
++struct screenshooter_output {
++ struct wl_output *output;
++ struct wl_buffer *buffer;
++ int width, height, offset_x, offset_y;
++ void *data;
++ struct wl_list link;
++};
++
++static void
++display_handle_geometry(void *data,
++ struct wl_output *wl_output,
++ int x,
++ int y,
++ int physical_width,
++ int physical_height,
++ int subpixel,
++ const char *make,
++ const char *model,
++ int transform)
++{
++ struct screenshooter_output *output;
++
++ output = wl_output_get_user_data(wl_output);
++
++ if (wl_output == output->output) {
++ output->offset_x = x;
++ output->offset_y = y;
++ }
++}
++
++static void
++display_handle_mode(void *data,
++ struct wl_output *wl_output,
++ uint32_t flags,
++ int width,
++ int height,
++ int refresh)
++{
++ struct screenshooter_output *output;
++
++ output = wl_output_get_user_data(wl_output);
++
++ if (wl_output == output->output && (flags & WL_OUTPUT_MODE_CURRENT)) {
++ output->width = width;
++ output->height = height;
++ }
++}
++
++static const struct wl_output_listener output_listener = {
++ display_handle_geometry,
++ display_handle_mode
++};
++
++static void
++screenshooter_done(void *data, struct weston_screenshooter_mtk *mtk_screenshooter)
++{
++ fprintf(stderr, "screenshooter_done\n");
++ buffer_copy_done = 1;
++}
++
++static const struct weston_screenshooter_mtk_listener screenshooter_mtk_listener =
++{
++ screenshooter_done
++};
++
++static void
++handle_global(void *data, struct wl_registry *registry,
++ uint32_t name, const char *interface, uint32_t version)
++{
++ static struct screenshooter_output *output;
++
++ if (strcmp(interface, "wl_output") == 0) {
++ output = xmalloc(sizeof *output);
++ output->output = wl_registry_bind(registry, name,
++ &wl_output_interface, 1);
++ wl_list_insert(&output_list, &output->link);
++ wl_output_add_listener(output->output, &output_listener, output);
++ } else if (strcmp(interface, "wl_shm") == 0) {
++ shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
++ } else if (strcmp(interface, "weston_screenshooter_mtk") == 0) {
++ mtk_screenshooter = wl_registry_bind(registry, name,
++ &weston_screenshooter_mtk_interface,
++ 1);
++ }
++}
++
++static void
++handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
++{
++ /* XXX: unimplemented */
++}
++
++static const struct wl_registry_listener registry_listener = {
++ handle_global,
++ handle_global_remove
++};
++
++static struct wl_buffer *
++create_shm_buffer(int width, int height, void **data_out)
++{
++ struct wl_shm_pool *pool;
++ struct wl_buffer *buffer;
++ int fd, size, stride;
++ void *data;
++
++ stride = width * 4;
++ size = stride * height;
++
++ fd = os_create_anonymous_file(size);
++ if (fd < 0) {
++ fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
++ size);
++ return NULL;
++ }
++
++ data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
++ if (data == MAP_FAILED) {
++ fprintf(stderr, "mmap failed: %m\n");
++ close(fd);
++ return NULL;
++ }
++
++ pool = wl_shm_create_pool(shm, fd, size);
++ close(fd);
++ buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
++ WL_SHM_FORMAT_XRGB8888);
++ wl_shm_pool_destroy(pool);
++
++ *data_out = data;
++ fprintf(stderr,"create_shm_buffer\n");
++ return buffer;
++}
++
++static void
++usage(int error_code)
++{
++ fprintf(stderr, "Usage: simple-screenshooter-mtk [OPTIONS]\n\n"
++ " -m dump mainscreen\n"
++ " -s dump subscreen\n"
++ " -h This help text! default dump all screens\n\n");
++
++ exit(error_code);
++}
++
++int main(int argc, char *argv[])
++{
++ struct wl_display *display;
++ struct wl_registry *registry;
++ struct screenshooter_output *output;
++ int i, width, height;
++ int mainscreen=0;
++ int subscreen=0;
++ for (i = 1; i < argc; i++) {
++ if (strcmp("-m", argv[i]) == 0)
++ mainscreen = 1;
++ else if (strcmp("-s", argv[i]) == 0)
++ subscreen = 1;
++ else if (strcmp("-h", argv[i]) == 0)
++ usage(EXIT_SUCCESS);
++ else
++ usage(EXIT_SUCCESS);
++ }
++
++ display = wl_display_connect(NULL);
++ if (display == NULL) {
++ fprintf(stderr, "failed to create display: %m\n");
++ return -1;
++ }
++
++ wl_list_init(&output_list);
++ registry = wl_display_get_registry(display);
++ wl_registry_add_listener(registry, ®istry_listener, NULL);
++ wl_display_dispatch(display);
++ wl_display_roundtrip(display);
++ if (mtk_screenshooter == NULL) {
++ fprintf(stderr, "display doesn't support screenshooter\n");
++ return -1;
++ }
++
++ weston_screenshooter_mtk_add_listener(mtk_screenshooter,
++ &screenshooter_mtk_listener,
++ NULL);
++
++ wl_list_for_each_reverse(output, &output_list, link) {
++ if(mainscreen == 1) {
++ output->buffer = create_shm_buffer(1920, 1080, &output->data);
++ weston_screenshooter_mtk_shoot(mtk_screenshooter,output->output,output->buffer);
++ buffer_copy_done = 0;
++ while (!buffer_copy_done)
++ wl_display_roundtrip(display);
++
++ break;
++ }
++ else if(subscreen == 1) {
++ subscreen = 0;
++ }
++ else {
++ output->buffer = create_shm_buffer(1920, 1080, &output->data);
++ weston_screenshooter_mtk_shoot(mtk_screenshooter,output->output,output->buffer);
++ buffer_copy_done = 0;
++ while (!buffer_copy_done)
++ wl_display_roundtrip(display);
++ }
++ }
++ fprintf(stderr,"end!!!!!\n");
++ return 0;
++}
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index bba22b3..064d8c2 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -236,6 +236,7 @@ struct drm_backend {
+ struct gbm_device *gbm;
+ struct wl_listener session_listener;
+ uint32_t gbm_format;
++ uint32_t writeback_connectors;
+
+ /* we need these parameters in order to not fail drmModeAddFB2()
+ * due to out of bounds dimensions, and then mistakenly set
+@@ -411,6 +412,9 @@ struct drm_output {
+ uint32_t connector_id;
+ struct drm_edid edid;
+
++ uint32_t wb_connector_id;
++ uint32_t wb_prop_id;
++
+ /* Holds the properties for the connector */
+ struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
+ /* Holds the properties for the CRTC */
+@@ -451,6 +455,7 @@ struct drm_output {
+ struct wl_listener recorder_frame_listener;
+
+ struct wl_event_source *pageflip_timer;
++ struct drm_fb *wb_fb;
+ };
+
+ static struct gl_renderer_interface *gl_renderer;
+@@ -477,6 +482,29 @@ wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
+ }
+ }
+
++static int
++_write_file(void *buf, int len, const char *file_name)
++{
++ int ret, nwrite = 0;
++
++ FILE *fp = fopen(file_name, "wb");
++ if (!fp)
++ {
++ fprintf(stderr,"debug: file %s open failed\n", file_name);
++ return -1;
++ }
++
++ while (nwrite < len) {
++ ret = fwrite(buf + nwrite, 1, len - nwrite, fp);
++ if (!ret)
++ break;
++ nwrite += ret;
++ }
++
++ fclose(fp);
++ return 0;
++}
++
+ static inline struct drm_output *
+ to_drm_output(struct weston_output *base)
+ {
+@@ -749,6 +777,40 @@ drm_output_update_msc(struct drm_output *output, unsigned int seq);
+ static void
+ drm_output_destroy(struct weston_output *output_base);
+
++static uint64_t
++drm_properties_get_writeback_fb_value(struct drm_backend *b,
++ uint32_t obj_id, uint32_t obj_type)
++{
++ drmModeObjectProperties *props;
++ drmModePropertyRes *prop;
++ unsigned i;
++ uint64_t value;
++
++ props = drmModeObjectGetProperties(b->drm.fd, obj_id, obj_type);
++ if (!props) {
++ weston_log("DRM error : get properties for object %u "
++ "of type %#x failed.\n", obj_id, obj_type);
++ return -1;
++ }
++
++ for (i = 0; i < props->count_props; i++) {
++ prop = drmModeGetProperty(b->drm.fd, props->props[i]);
++ if (!prop)
++ continue;
++
++ if (strcmp(prop->name, "WRITEBACK_FB_ID") == 0)
++ break;
++ }
++
++
++ value = prop->prop_id;
++
++ drmModeFreeObjectProperties(props);
++
++ return value;
++}
++
++
+ /**
+ * Returns true if the plane can be used on the given output for its current
+ * repaint cycle.
+@@ -2053,6 +2115,13 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
+ ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
+ ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
+ output->crtc_id);
++ if(output->wb_connector_id) {
++ if (drmModeAtomicAddProperty(req, output->wb_connector_id,
++ output->props_conn[WDRM_CONNECTOR_CRTC_ID].prop_id,
++ output->crtc_id) < 0)
++ return -1;
++
++ }
+ } else {
+ ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
+ ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
+@@ -2095,6 +2164,12 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
+ }
+ }
+
++ if(output->base.screenshoot_dump == 1 && output->wb_connector_id) {
++ ret = drmModeAtomicAddProperty(req, output->wb_connector_id,
++ output->wb_prop_id,
++ output->wb_fb->fb_id);
++ }
++
+ return 0;
+ }
+
+@@ -2605,6 +2680,7 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
+ uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
+ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
+ WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
++ char filename[64];
+
+ /* During the initial modeset, we can disable CRTCs which we don't
+ * actually handle during normal operation; this will give us events
+@@ -2612,6 +2688,14 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
+ if (!output || !output->base.enabled)
+ return;
+
++ if(output->base.screenshoot_dump == 1 && output->wb_connector_id) {
++ snprintf(filename, 64, "/tmp/screen_dump_%u",
++ weston_compositor_get_time());
++ _write_file(output->wb_fb->map, output->wb_fb->size, filename);
++ output->base.screenshoot_needed = 0;
++ output->base.screenshoot_dump = 0;
++ }
++
+ drm_output_update_msc(output, frame);
+
+ assert(b->atomic_modeset);
+@@ -5011,6 +5095,24 @@ create_output_for_connector(struct drm_backend *b,
+
+ weston_compositor_add_pending_output(&output->base, b->compositor);
+
++ if(b->writeback_connectors) {
++ for(i=0; ;i++) {
++ if(b->writeback_connectors & (1 << i))
++ break;
++ }
++ output->wb_connector_id = resources->connectors[i];
++ output->wb_prop_id = drm_properties_get_writeback_fb_value(b,
++ resources->connectors[i],
++ DRM_MODE_OBJECT_CONNECTOR);
++ b->writeback_connectors &= ~(1 << i);
++ weston_log("output->wb_connector_id=%d,output->wb_prop_id=%d,output->connector_id=%d\n",output->wb_connector_id,output->wb_prop_id,output->connector_id);
++ weston_log("b->writeback_connectors=%d \n",b->writeback_connectors);
++ }
++
++ output->wb_fb = drm_fb_create_dumb(b, 1920, 1080, DRM_FORMAT_RGB888);
++ if (!output->wb_fb)
++ weston_log("writeback drm_fb_create_dumb failed\n");
++
+ return 0;
+
+ err_output:
+@@ -5029,6 +5131,7 @@ create_outputs(struct drm_backend *b, struct udev_device *drm_device)
+ drmModeConnector *connector;
+ drmModeRes *resources;
+ int i;
++ b->writeback_connectors = 0;
+
+ resources = drmModeGetResources(b->drm.fd);
+ if (!resources) {
+@@ -5042,6 +5145,17 @@ create_outputs(struct drm_backend *b, struct udev_device *drm_device)
+ b->max_height = resources->max_height;
+
+ for (i = 0; i < resources->count_connectors; i++) {
++ connector = drmModeGetConnector(b->drm.fd,
++ resources->connectors[i]);
++ if (connector == NULL)
++ continue;
++
++ if (connector->connection == DRM_MODE_DISCONNECTED) {
++ b->writeback_connectors |= 1 << i;
++ }
++ }
++
++ for (i = 0; i < resources->count_connectors; i++) {
+ int ret;
+
+ connector = drmModeGetConnector(b->drm.fd,
+@@ -5853,6 +5967,7 @@ weston_backend_init(struct weston_compositor *compositor,
+ b = drm_backend_create(compositor, &config);
+ if (b == NULL)
+ return -1;
++ screenshooter_mtk_create(compositor);
+
+ return 0;
+ }
+diff --git a/libweston/compositor.c b/libweston/compositor.c
+index fb647da..9d084f5 100644
+--- a/libweston/compositor.c
++++ b/libweston/compositor.c
+@@ -2636,6 +2636,9 @@ weston_output_schedule_repaint(struct weston_output *output)
+ compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
+ return;
+
++ if(output->screenshoot_needed)
++ output->screenshoot_dump = 1;
++
+ if (!output->repaint_needed)
+ TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
+
+diff --git a/libweston/compositor.h b/libweston/compositor.h
+index 6070c77..dea88dc 100644
+--- a/libweston/compositor.h
++++ b/libweston/compositor.h
+@@ -183,6 +183,9 @@ struct weston_output {
+ REPAINT_AWAITING_COMPLETION, /**< last repaint not yet finished */
+ } repaint_status;
+
++ int screenshoot_needed;
++ int screenshoot_dump;
++
+ /** If repaint_status is REPAINT_SCHEDULED, contains the time the
+ * next repaint should be run */
+ struct timespec next_repaint;
+diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c
+index df84a9f..b45db93 100644
+--- a/libweston/pixel-formats.c
++++ b/libweston/pixel-formats.c
+@@ -145,6 +145,8 @@ static const struct pixel_format_info pixel_format_table[] = {
+ },
+ {
+ .format = DRM_FORMAT_RGB888,
++ .depth = 24,
++ .bpp = 24,
+ },
+ {
+ .format = DRM_FORMAT_BGR888,
+diff --git a/libweston/weston-screenshooter-mtk.c b/libweston/weston-screenshooter-mtk.c
+new file mode 100644
+index 0000000..7ad8f97
+--- /dev/null
++++ b/libweston/weston-screenshooter-mtk.c
+@@ -0,0 +1,129 @@
++/*
++ * Copyright © 2008-2011 Kristian Høgsberg
++ *
++ * 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 <stdio.h>
++#include <string.h>
++#include <linux/input.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <sys/uio.h>
++
++#include "compositor.h"
++#include "weston-configure-mtk-server-protocol.h"
++#include "shared/helpers.h"
++
++#include "wcap/wcap-decode.h"
++
++struct screenshooter {
++ struct weston_compositor *ec;
++ struct wl_global *global;
++ struct wl_client *client;
++ //struct weston_process process;
++ struct wl_listener destroy_listener;
++};
++
++struct screenshooter_frame_listener {
++ struct wl_listener listener;
++ struct weston_buffer *buffer;
++ weston_screenshooter_done_func_t done;
++ void *data;
++};
++
++static void
++weston_screenshooter_mtk_shoot(struct wl_client *client,
++ struct wl_resource *resource,
++ struct wl_resource *output_resource,
++ struct wl_resource *buffer_resource)
++{
++ struct weston_output *output =
++ wl_resource_get_user_data(output_resource);
++ struct weston_buffer *buffer =
++ weston_buffer_from_resource(buffer_resource);
++ weston_log("weston_screenshooter_mtk_shoot.\n");
++ output->screenshoot_needed = 1;
++ weston_output_schedule_repaint(output);
++ if (buffer == NULL) {
++ wl_resource_post_no_memory(resource);
++ return;
++ }
++
++ weston_screenshooter_mtk_send_done(resource);
++}
++
++static const struct weston_screenshooter_mtk_interface screenshooter_mtk_implementation = {
++ weston_screenshooter_mtk_shoot
++};
++
++static void
++bind_screenshooter_mtk(struct wl_client *client,
++ void *data, uint32_t version, uint32_t id)
++{
++ struct screenshooter *shooter = data;
++ struct wl_resource *resource;
++
++ resource = wl_resource_create(client,
++ &weston_screenshooter_mtk_interface, 1, id);
++
++ if (resource == NULL) {
++ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
++ "screenshooter failed: permission denied");
++ wl_client_post_no_memory(client);
++ return;
++ }
++
++ wl_resource_set_implementation(resource, &screenshooter_mtk_implementation,
++ data, NULL);
++}
++
++static void
++screenshooter_destroy(struct wl_listener *listener, void *data)
++{
++ struct screenshooter *shooter =
++ container_of(listener, struct screenshooter, destroy_listener);
++
++ wl_global_destroy(shooter->global);
++ free(shooter);
++}
++
++WL_EXPORT void
++screenshooter_mtk_create(struct weston_compositor *ec)
++{
++ struct screenshooter *shooter;
++
++ shooter = malloc(sizeof *shooter);
++ if (shooter == NULL)
++ return;
++
++ shooter->ec = ec;
++ shooter->global = wl_global_create(ec->wl_display,
++ &weston_screenshooter_mtk_interface, 1,
++ shooter, bind_screenshooter_mtk);
++
++ shooter->destroy_listener.notify = screenshooter_destroy;
++ wl_signal_add(&ec->destroy_signal, &shooter->destroy_listener);
++}
+diff --git a/protocol/weston-configure-mtk.xml b/protocol/weston-configure-mtk.xml
+new file mode 100644
+index 0000000..e19a2ad
+--- /dev/null
++++ b/protocol/weston-configure-mtk.xml
+@@ -0,0 +1,37 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<protocol name="weston_configure_mtk">
++
++ <copyright>
++ Copyright (C) 2016 MediaTek
++
++ 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.
++ </copyright>
++
++ <interface name="weston_screenshooter_mtk" version="1">
++ <request name="shoot">
++ <arg name="output" type="object" interface="wl_output"/>
++ <arg name="buffer" type="object" interface="wl_buffer"/>
++ </request>
++ <event name="done">
++ </event>
++ </interface>
++
++</protocol>
++
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0008-PATCH-weston-add-surface-overlay-assignment-interfac.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0008-PATCH-weston-add-surface-overlay-assignment-interfac.patch
new file mode 100644
index 0000000..063dba6
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0008-PATCH-weston-add-surface-overlay-assignment-interfac.patch
@@ -0,0 +1,278 @@
+From 949565b2683a3a67060698132a52ea26c75d9952 Mon Sep 17 00:00:00 2001
+From: Qian Hu <Qian.Hu@mediatek.com>
+Date: Tue, 24 Sep 2019 15:01:45 +0800
+Subject: [PATCH 8/8] [PATCH] weston: add surface overlay assignment interface
+
+add surface overlay assignment interface
+
+Signed-off-by: Qian Hu <Qian.Hu@mediatek.com>
+---
+ Makefile.am | 6 +-
+ compositor/main.c | 1 +
+ libweston/compositor.h | 11 ++++
+ libweston/weston-configure-mtk.c | 126 +++++++++++++++++++++++++++++++++++++++
+ libweston/weston-configure-mtk.h | 54 +++++++++++++++++
+ 5 files changed, 197 insertions(+), 1 deletion(-)
+ create mode 100644 libweston/weston-configure-mtk.c
+ create mode 100644 libweston/weston-configure-mtk.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 7efa5a0..008bdfe 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -97,6 +97,8 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ libweston/pixel-formats.c \
+ libweston/pixel-formats.h \
+ libweston/weston-screenshooter-mtk.c \
++ libweston/weston-configure-mtk.c \
++ libweston/weston-configure-mtk.h \
+ shared/helpers.h \
+ shared/matrix.c \
+ shared/matrix.h \
+@@ -677,7 +679,9 @@ nodist_weston_simple_configure_mtk_SOURCES = \
+ protocol/fullscreen-shell-unstable-v1-protocol.c \
+ protocol/fullscreen-shell-unstable-v1-client-protocol.h \
+ protocol/linux-dmabuf-unstable-v1-protocol.c \
+- protocol/linux-dmabuf-unstable-v1-client-protocol.h
++ protocol/linux-dmabuf-unstable-v1-client-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-client-protocol.h
+ weston_simple_configure_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+ weston_simple_configure_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
+ BUILT_SOURCES += protocol/linux-dmabuf-unstable-v1-client-protocol.h
+diff --git a/compositor/main.c b/compositor/main.c
+index b5b4fc5..21c501c 100644
+--- a/compositor/main.c
++++ b/compositor/main.c
+@@ -52,6 +52,7 @@
+ #include "git-version.h"
+ #include "version.h"
+ #include "weston.h"
++#include "../libweston/weston-configure-mtk.h"
+
+ #include "compositor-drm.h"
+ #include "compositor-headless.h"
+diff --git a/libweston/compositor.h b/libweston/compositor.h
+index 8736691..ba577b7 100644
+--- a/libweston/compositor.h
++++ b/libweston/compositor.h
+@@ -1362,6 +1362,16 @@ struct weston_surface_state {
+ struct weston_buffer_viewport buffer_viewport;
+ };
+
++/*
++ * For setting whether the views on this surface walk
++ * overlay path; on==>1, off==>0
++*/
++struct config_switch{
++ struct wl_resource *resource;
++ void *private;
++ int sprites_switch;
++};
++
+ struct weston_surface_activation_data {
+ struct weston_surface *surface;
+ struct weston_seat *seat;
+@@ -1483,6 +1493,7 @@ struct weston_surface {
+
+ /* An list of per seat pointer constraints. */
+ struct wl_list pointer_constraints;
++ struct config_switch *config_switch;
+ };
+
+ struct weston_subsurface {
+diff --git a/libweston/weston-configure-mtk.c b/libweston/weston-configure-mtk.c
+new file mode 100644
+index 0000000..185f91c
+--- /dev/null
++++ b/libweston/weston-configure-mtk.c
+@@ -0,0 +1,126 @@
++#include "config.h"
++#include <fcntl.h>
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <limits.h>
++#include <stdarg.h>
++#include <assert.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++#include <sys/wait.h>
++#include <sys/socket.h>
++#include <sys/utsname.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <math.h>
++#include <linux/input.h>
++#include <dlfcn.h>
++#include <signal.h>
++#include <setjmp.h>
++#include <sys/time.h>
++#include <time.h>
++#include <errno.h>
++
++#include "timeline.h"
++
++#include "compositor.h"
++//#include "scaler-server-protocol.h"
++#include "shared/helpers.h"
++#include "shared/os-compatibility.h"
++#include "shared/timespec-util.h"
++#include "git-version.h"
++#include "version.h"
++
++#include "weston-configure-mtk.h"
++#include "weston-configure-mtk-server-protocol.h"
++
++static void
++config_set_sprite_switch(struct wl_client *client,
++ struct wl_resource *resource,
++ int32_t spr_switch)
++{
++ struct config_switch *configure = wl_resource_get_user_data(resource);
++
++ configure->sprites_switch = spr_switch;
++}
++
++static const struct config_switch_set_interface switch_set_interface = {
++ config_set_sprite_switch,
++};
++
++static struct config_switch *
++config_interface_create(struct weston_surface *surface)
++{
++ struct config_switch *config_switch;
++
++ config_switch = zalloc(sizeof *config_switch);
++ if (config_switch == NULL)
++ return NULL;
++
++ config_switch->private = (void *)surface;
++ surface->config_switch = config_switch;
++
++ return config_switch;
++}
++
++static void
++config_switch_connect(struct wl_client *client, struct wl_resource *resource,
++ struct wl_resource *wl_surface, uint32_t id)
++{
++ struct config_switch *config_switch = wl_resource_get_user_data(resource);
++ struct weston_surface *surface = wl_resource_get_user_data(wl_surface);
++
++ config_switch = config_interface_create(surface);
++ if (config_switch == NULL) {
++ wl_resource_post_no_memory(resource);
++ return;
++ }
++
++ config_switch->resource =
++ wl_resource_create(client, &config_switch_set_interface,
++ wl_resource_get_version(resource), id);
++ if (config_switch->resource == NULL) {
++ wl_resource_post_no_memory(resource);
++ return;
++ }
++ wl_resource_set_implementation(config_switch->resource, &switch_set_interface,
++ config_switch, NULL);
++}
++
++static const struct config_switch_interface switch_interface = {
++ config_switch_connect,
++};
++
++static void
++bind_config_switch(struct wl_client *client,
++ void *data, uint32_t version, uint32_t id)
++{
++ struct weston_compositor *compositor = data;
++ struct wl_resource *resource;
++
++ resource = wl_resource_create(client, &config_switch_interface,
++ MIN(version, 1), id);
++ if (resource == NULL) {
++ wl_client_post_no_memory(client);
++ return;
++ }
++
++ wl_resource_set_implementation(resource, &switch_interface,
++ compositor, NULL);
++}
++
++WL_EXPORT int
++config_switch_global_create(struct weston_compositor *ec)
++{
++ if(!ec)
++ return -1;
++ if (!wl_global_create(ec->wl_display, &config_switch_interface, 1,
++ ec, bind_config_switch)){
++ fprintf(stderr, "error: failed to config_switch_global_create: %s\n", dlerror());
++ return -1;
++ }
++ return 0;
++}
++
+diff --git a/libweston/weston-configure-mtk.h b/libweston/weston-configure-mtk.h
+new file mode 100644
+index 0000000..0f093fe
+--- /dev/null
++++ b/libweston/weston-configure-mtk.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright © 2008-2011 Kristian Høgsberg
++ * Copyright © 2012 Collabora, Ltd.
++ *
++ * 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 _APP_CONFIGURE_EXTENSION_H_
++#define _APP_CONFIGURE_EXTENSION_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stdbool.h>
++#include <time.h>
++#include <pixman.h>
++#include <xkbcommon/xkbcommon.h>
++
++#include <wayland-server.h>
++
++#include "version.h"
++#include "matrix.h"
++#include "config-parser.h"
++#include "zalloc.h"
++#include "timeline-object.h"
++
++int config_switch_global_create(struct weston_compositor *ec);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
++
+--
+2.6.4
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0008-weston-add-mtk-test-client.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0008-weston-add-mtk-test-client.patch
new file mode 100644
index 0000000..0036894
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0008-weston-add-mtk-test-client.patch
@@ -0,0 +1,1295 @@
+From 190e1349858bba7e103b03a0f242575425066300 Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Thu, 3 May 2018 08:35:18 +0800
+Subject: [PATCH] weston: add mtk test client
+
+add mtk test client
+Test: OK
+
+Change-Id: I89f50f00414c426b00424ab2dc298647330472a6
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ Makefile.am | 15 +
+ clients/simple-configure-mtk.c | 1230 ++++++++++++++++++++++++++++++++++++++++
+ configure.ac | 1 +
+ 3 files changed, 1246 insertions(+)
+ create mode 100644 clients/simple-configure-mtk.c
+
+diff --git a/Makefile.am b/Makefile.am
+index e450b95..576b4a1 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -657,6 +657,21 @@ nodist_weston_simple_screenshooter_mtk_SOURCES = \
+ weston_simple_screenshooter_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+ weston_simple_screenshooter_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
+
++if BUILD_SIMPLE_CONFIGURE_MTK_CLIENT
++demo_clients += weston-simple-configure-mtk
++weston_simple_configure_mtk_SOURCES = clients/simple-configure-mtk.c
++nodist_weston_simple_configure_mtk_SOURCES = \
++ protocol/xdg-shell-unstable-v6-protocol.c \
++ protocol/xdg-shell-unstable-v6-client-protocol.h \
++ protocol/fullscreen-shell-unstable-v1-protocol.c \
++ protocol/fullscreen-shell-unstable-v1-client-protocol.h \
++ protocol/linux-dmabuf-unstable-v1-protocol.c \
++ protocol/linux-dmabuf-unstable-v1-client-protocol.h
++weston_simple_configure_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
++weston_simple_configure_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
++BUILT_SOURCES += protocol/linux-dmabuf-unstable-v1-client-protocol.h
++endif
++
+ noinst_LTLIBRARIES += libtoytoolkit.la
+
+ libtoytoolkit_la_SOURCES = \
+diff --git a/clients/simple-configure-mtk.c b/clients/simple-configure-mtk.c
+new file mode 100644
+index 0000000..f94497e
+--- /dev/null
++++ b/clients/simple-configure-mtk.c
+@@ -0,0 +1,1230 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdbool.h>
++#include <math.h>
++#include <assert.h>
++#include <sys/mman.h>
++#include <signal.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <linux/input.h>
++
++#include <wayland-client.h>
++#include <wayland-cursor.h>
++
++#include <drm_fourcc.h>
++#include <xf86drm.h>
++#include <xf86drmMode.h>
++
++#include <sys/types.h>
++#include <unistd.h>
++
++//#include "ivi-application-client-protocol.h"
++#include "xdg-shell-unstable-v6-client-protocol.h"
++#include "linux-dmabuf-unstable-v1-client-protocol.h"
++#include "fullscreen-shell-unstable-v1-client-protocol.h"
++
++#include <shared/platform.h>
++
++//#define IVI_SURFACE_ID 9000
++#define MAX_IMAGE 16
++#define ALIGN(X,bit) ((X + bit-1) & (~(bit-1)))
++#define MAX_DMABUF_PLANES 4
++#define RES_NUM 4
++#define MAX_LEN 60
++
++struct window;
++struct seat;
++
++struct display {
++ struct wl_display *display;
++ struct wl_registry *registry;
++ struct wl_compositor *compositor;
++ struct zxdg_shell_v6 *shell;
++ struct zwp_fullscreen_shell_v1 *fshell;
++ //struct ivi_application *ivi_application;
++ struct wl_seat *seat;
++ struct wl_pointer *pointer;
++ struct wl_touch *touch;
++ struct wl_keyboard *keyboard;
++ struct wl_shm *shm;
++ struct zwp_linux_dmabuf_v1 *dmabuf;
++ struct wl_list output_list; /* struct output_unit::link */
++ struct wl_cursor_theme *cursor_theme;
++ struct wl_cursor *default_cursor;
++ struct wl_surface *cursor_surface;
++ struct window *window;
++};
++
++struct geometry {
++ int width, height;
++};
++
++struct buffer {
++ struct wl_buffer *buffer;
++ void *dma_map;
++ int busy;
++};
++
++struct file_arg{
++ char filename[MAX_LEN];
++ int width;
++ int height;
++ int format;
++};
++
++struct window {
++ struct display *display;
++ struct geometry geometry, window_size;
++ bool wait_for_configure;
++ struct {
++ struct file_arg fProp;
++ struct buffer out_bufs[RES_NUM];
++ } image;
++ struct img_texture *tex;
++ uint32_t benchmark_time, frames;
++ struct wl_surface *surface;
++ struct zxdg_surface_v6 *xdg_surface;
++ struct zxdg_toplevel_v6 *xdg_toplevel;
++ //struct ivi_surface *ivi_surface;
++ struct wl_callback *callback;
++ int fullscreen, opaque, buffer_size, overlay, format;
++ enum wl_output_transform transform;
++ int drm_card_fd;
++};
++
++struct img_texture {
++ struct context *ctx;
++
++ /* input */
++ int width;
++ int height;
++ int drm_format;
++ int bpp;
++ int plane_nums;
++
++ int pitch[MAX_DMABUF_PLANES];
++ int offset[MAX_DMABUF_PLANES];
++ int fds[MAX_DMABUF_PLANES];
++ int handle[MAX_DMABUF_PLANES];
++
++ void *texbuf;
++ int size;
++};
++
++typedef enum _IMG_FORMAT_E {
++ IMG_FORMAT_RGB565 = 0,
++ IMG_FORMAT_XRGB8888,
++ IMG_FORMAT_ARGB8888,
++ IMG_FORMAT_YUYV,
++ IMG_FORMAT_NV12,
++ IMG_FORMAT_NV16,
++ IMG_FORMAT_YUV420,
++ IMG_FORMAT_YVU420,
++ IMG_FORMAT_LAST,
++} IMG_FORMAT_T;
++
++struct drm_fourcc_info {
++ unsigned int drm_format;
++ int plane_cnt;
++ int bpp;
++};
++
++static struct drm_fourcc_info fourcc_tbl[] = {
++ {DRM_FORMAT_RGB565, 1, 16},
++ {DRM_FORMAT_RGBA5551, 1, 16},
++ {DRM_FORMAT_RGBA4444, 1, 16},
++ {DRM_FORMAT_XRGB8888, 1, 32},
++ {DRM_FORMAT_XBGR8888, 1, 32},
++ {DRM_FORMAT_RGBX8888, 1, 32},
++ {DRM_FORMAT_BGRX8888, 1, 32},
++ {DRM_FORMAT_ARGB8888, 1, 32},
++ {DRM_FORMAT_ABGR8888, 1, 32},
++ {DRM_FORMAT_RGBA8888, 1, 32},
++ {DRM_FORMAT_BGRA8888, 1, 32},
++ {DRM_FORMAT_YUYV, 1, 16},
++ {DRM_FORMAT_VYUY, 1, 16},
++ {DRM_FORMAT_NV12, 2, 12},
++ {DRM_FORMAT_NV21, 2, 12},
++ {DRM_FORMAT_NV16, 2, 16},
++ {DRM_FORMAT_NV61, 2, 16},
++ {DRM_FORMAT_YUV420, 3, 12},
++ {DRM_FORMAT_YVU420, 3, 12},
++ {0, 0, 0},
++};
++
++static int running = 1;
++static int debug = 0;
++
++static void
++redraw(void *data, struct wl_callback *callback, uint32_t time);
++
++static int _format_transfer(int format, int *drm_format)
++{
++ int new_format;
++
++ if (!drm_format)
++ return -1;
++
++ switch (format) {
++ case IMG_FORMAT_RGB565:
++ new_format = DRM_FORMAT_RGB565;
++ break;
++ case IMG_FORMAT_XRGB8888:
++ new_format = DRM_FORMAT_XRGB8888;
++ break;
++ case IMG_FORMAT_ARGB8888:
++ new_format = DRM_FORMAT_ARGB8888;
++ break;
++ case IMG_FORMAT_YUYV:
++ new_format = DRM_FORMAT_YUYV;
++ break;
++ case IMG_FORMAT_NV12:
++ new_format = DRM_FORMAT_NV12;
++ break;
++ case IMG_FORMAT_NV16:
++ new_format = DRM_FORMAT_NV16;
++ break;
++ case IMG_FORMAT_YUV420:
++ new_format = DRM_FORMAT_YUV420;
++ break;
++ case IMG_FORMAT_YVU420:
++ new_format = DRM_FORMAT_YVU420;
++ break;
++ default:
++ return -2;
++ }
++ *drm_format = new_format;
++
++ return 0;
++}
++
++static struct drm_fourcc_info *
++get_drm_format_info(unsigned int format)
++{
++ int i;
++
++ for (i = 0; ; i++) {
++ if ( format == fourcc_tbl[i].drm_format){
++ return &fourcc_tbl[i];
++ }
++ if ( fourcc_tbl[i].drm_format == 0)
++ break;
++ }
++ return NULL;
++}
++
++static char *
++_get_tex_resource(int drifd, struct img_texture *tex)
++{
++ void *map = NULL;
++ struct drm_mode_create_dumb create_arg;
++ struct drm_mode_map_dumb map_arg;
++ struct drm_prime_handle prime_arg;
++ struct drm_fourcc_info *format_info;
++ int i, ret;
++ unsigned int alloc_size;
++
++ memset(&create_arg, 0, sizeof(create_arg));
++ memset(&map_arg, 0, sizeof(map_arg));
++ memset(&prime_arg, 0, sizeof(prime_arg));
++
++ for(i = 0; i < MAX_DMABUF_PLANES; i ++ )
++ tex->fds[i] = -1;
++
++ format_info = get_drm_format_info(tex->drm_format);
++ if (format_info == NULL)
++ return NULL;
++
++ tex->bpp = format_info->bpp;
++ if (format_info->plane_cnt == 3) {
++ if (format_info->bpp == 12) {
++ tex->pitch[0] = ALIGN(tex->width, 16);
++ tex->pitch[1] = tex->pitch[0] / 2;
++ tex->pitch[2] = tex->pitch[0] / 2;
++ tex->offset[0] = 0;
++ tex->offset[1] = tex->pitch[0] * tex->height;
++ tex->offset[2] = tex->offset[1] + tex->pitch[1] * tex->height / 2;
++ alloc_size = tex->offset[2] + tex->pitch[2] * tex->height / 2;
++ } else {
++ fprintf(stderr,"debug: please add new format 0x%x\n", tex->drm_format);
++ return NULL;
++ }
++ } else if (format_info->plane_cnt == 2) {
++ tex->pitch[0] = ALIGN(tex->width, 16);
++ tex->offset[0] = 0;
++ if (format_info->bpp == 16) {
++ tex->pitch[1] = tex->pitch[0];
++ tex->offset[1] = tex->pitch[0] * tex->height;
++ alloc_size = tex->offset[1] + tex->pitch[1] * tex->height;
++ fprintf(stderr,"debug: %s %d alloc_size = %d o/p [%d %d]\n",
++ __FUNCTION__, __LINE__, alloc_size, tex->offset[1], tex->pitch[1]);
++ }
++ else if (format_info->bpp == 12) {
++ tex->pitch[1] = tex->pitch[0] / 2;
++ tex->offset[1] = tex->pitch[0] * tex->height;
++ alloc_size = tex->offset[1] + tex->pitch[1] * tex->height;
++ } else {
++ fprintf(stderr,"debug: please add new format 0x%x\n", tex->drm_format);
++ return NULL;
++ }
++ } else {
++ tex->pitch[0] = ALIGN(tex->width * tex->bpp / 8, 16);
++ tex->offset[0] = 0;
++ alloc_size = tex->pitch[0] * tex->height;
++ }
++
++ create_arg.bpp = 8;
++ create_arg.width = alloc_size;
++ create_arg.height = 1;
++
++ ret = drmIoctl(drifd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
++ if (ret) {
++ fprintf(stderr,"error: drmIoctl %d DRM_IOCTL_MODE_CREATE_DUMB fail %d\n", drifd, ret);
++ return NULL;
++ }
++
++ map_arg.handle = create_arg.handle;
++
++ ret = drmIoctl(drifd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
++ if (ret) {
++ fprintf(stderr,"error: drmIoctl DRM_IOCTL_MODE_MAP_DUMB fail %d\n", ret);
++ return NULL;
++ }
++
++ map = mmap(0, create_arg.size, PROT_WRITE|PROT_READ , MAP_SHARED, drifd, map_arg.offset);
++ if (map == MAP_FAILED) {
++ fprintf(stderr,"error: mmap fail : %p\n", map);
++ return NULL;
++ }
++
++ prime_arg.handle = create_arg.handle;
++ prime_arg.flags = DRM_CLOEXEC;
++ ret = drmIoctl(drifd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_arg);
++ if (ret || prime_arg.fd == -1) {
++ fprintf(stderr,"error: drmIoctl DRM_IOCTL_PRIME_HANDLE_TO_FD fail %d fd=%d\n",ret,prime_arg.fd);
++ return NULL;
++ }
++
++ for (i = 0; i < format_info->plane_cnt; i++) {
++ tex->fds[i] = prime_arg.fd;
++ tex->handle[i] = create_arg.handle;
++ }
++ tex->plane_nums = format_info->plane_cnt;
++ tex->texbuf = map;
++ tex->size = create_arg.size;
++
++ return map;
++}
++
++static int
++init_img_texture(struct window *window)
++{
++ int ret;
++ struct img_texture *tex;
++ tex = malloc(sizeof *tex);
++ if (tex == NULL)
++ return -1;
++
++ ret = _format_transfer(window->image.fProp.format, &(tex->drm_format));
++ if (ret < 0)
++ return -1;
++
++ tex->width = window->image.fProp.width;
++ tex->height= window->image.fProp.height;
++
++ window->tex = tex;
++ return 0;
++}
++
++static void
++buffer_release(void *data, struct wl_buffer *buffer)
++{
++ struct buffer *mybuf = data;
++
++ mybuf->busy = 0;
++}
++
++static const struct wl_buffer_listener buffer_listener = {
++ buffer_release
++};
++
++static void
++create_succeeded(void *data,
++ struct zwp_linux_buffer_params_v1 *params,
++ struct wl_buffer *new_buffer)
++{
++ struct buffer *buffer = data;
++
++ buffer->buffer = new_buffer;
++ wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
++
++ zwp_linux_buffer_params_v1_destroy(params);
++}
++
++static void
++create_failed(void *data, struct zwp_linux_buffer_params_v1 *params)
++{
++ struct buffer *buffer = data;
++
++ buffer->buffer = NULL;
++
++ zwp_linux_buffer_params_v1_destroy(params);
++
++ running = false;
++
++ fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
++}
++
++static const struct zwp_linux_buffer_params_v1_listener params_listener = {
++ create_succeeded,
++ create_failed
++};
++
++static int
++create_dmabuf_buffer(struct display *display, struct buffer *buffer)
++{
++ struct zwp_linux_buffer_params_v1 *params;
++ struct img_texture *cbtex = display->window->tex;
++ uint64_t modifier;
++ uint32_t flags;
++ int i;
++ /* output */
++ buffer->dma_map = _get_tex_resource(display->window->drm_card_fd, cbtex);
++
++ if (buffer->dma_map == NULL) {
++ fprintf(stderr, "error: _get_tex_resource failed\n");
++ return -1;
++ }
++
++ modifier = 0;
++ params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
++
++ for(i = 0; i < cbtex->plane_nums; i ++)
++ {
++ zwp_linux_buffer_params_v1_add(params,
++ cbtex->fds[i],
++ i, /* plane_idx */
++ cbtex->offset[i],/* offset */
++ cbtex->pitch[i],
++ modifier >> 32,
++ modifier & 0xffffffff);
++ }
++ zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, buffer);
++ zwp_linux_buffer_params_v1_create(params,
++ cbtex->width,
++ cbtex->height,
++ cbtex->drm_format,
++ flags);
++
++ /* params is destroyed by the event handlers */
++ wl_display_roundtrip(display->display);
++ if (buffer->buffer == NULL) {
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++_load_file(void *buf, int len, const char *file_name)
++{
++ int ret, nread = 0;
++
++ FILE *fp = fopen(file_name, "rb");
++ if (!fp)
++ {
++ fprintf(stderr,"debug: file %s open failed\n", file_name);
++ return -1;
++ }
++
++ while (nread < len) {
++ ret = fread(buf + nread, 1, len - nread, fp);
++ if (!ret)
++ break;
++ nread += ret;
++ }
++
++ fclose(fp);
++ return 0;
++}
++
++static int
++_kms_device_fd(void)
++{
++ int i;
++ bool has_conn = false;
++ for (i = 0; i < 8; ++i) {
++ char path[99];
++ sprintf(path, "/dev/dri/card%d", i);
++ fprintf(stderr, "debug: trying %s\n", path);
++ int fd = open(path, O_RDWR | O_CLOEXEC);
++ if (fd >= 0) {
++ drmModeResPtr mr = drmModeGetResources(fd);
++ if (mr) {
++ has_conn = mr->count_connectors > 0;
++ drmModeFreeResources(mr);
++ }
++ if (has_conn) {
++ fprintf(stderr, "debug: using %s\n", path);
++ return fd;
++ }
++ close(fd);
++ }
++ }
++ return -1;
++}
++
++static void
++handle_xdg_surface_configure(void *data, struct zxdg_surface_v6 *surface,
++ uint32_t serial)
++{
++ struct window *window = data;
++ fprintf(stderr, "handle_xdg_surface_configure\n");
++
++ zxdg_surface_v6_ack_configure(surface, serial);
++
++ if (window->wait_for_configure) {
++ redraw(window, NULL, 0);
++ window->wait_for_configure = false;
++ }
++}
++
++static const struct zxdg_surface_v6_listener xdg_surface_listener = {
++ handle_xdg_surface_configure,
++};
++
++
++static void
++handle_toplevel_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
++ int32_t width, int32_t height,
++ struct wl_array *states)
++{
++ struct window *window = data;
++ uint32_t *p;
++
++ window->fullscreen = 0;
++ wl_array_for_each(p, states) {
++ uint32_t state = *p;
++ switch (state) {
++ case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
++ window->fullscreen = 1;
++ break;
++ }
++ }
++
++ if (width > 0 && height > 0) {
++ if (!window->fullscreen) {
++ window->window_size.width = width;
++ window->window_size.height = height;
++ }
++ window->geometry.width = width;
++ window->geometry.height = height;
++ } else if (!window->fullscreen) {
++ window->geometry = window->window_size;
++ }
++
++ /*if (window->native)
++ wl_egl_window_resize(window->native,
++ window->geometry.width,
++ window->geometry.height, 0, 0);*/
++}
++
++static void
++handle_toplevel_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
++{
++ running = 0;
++}
++
++static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
++ handle_toplevel_configure,
++ handle_toplevel_close,
++};
++/*
++static void
++handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface,
++ int32_t width, int32_t height)
++{
++
++}
++
++static const struct ivi_surface_listener ivi_surface_listener = {
++ handle_ivi_surface_configure,
++};
++*/
++static struct buffer *
++window_next_buffer(struct window *window)
++{
++ struct buffer *buffer = NULL;
++ int i, ret = 0;
++
++ for(i = 0; i < RES_NUM; i++) {
++ if (!window->image.out_bufs[i].busy) {
++ buffer = &window->image.out_bufs[i];
++ break;
++ }
++ }
++
++ if (!buffer)
++ return NULL;
++
++ if (!buffer->buffer) {
++ ret = create_dmabuf_buffer(window->display, buffer);
++ if (ret < 0)
++ return NULL;
++ if(i%2)
++ _load_file(buffer->dma_map, window->tex->size, window->image.fProp.filename);
++ else
++ memset(buffer->dma_map, 0, window->tex->size);
++ }
++
++ return buffer;
++}
++
++static void
++create_surface(struct window *window)
++{
++ struct display *display = window->display;
++
++ window->surface = wl_compositor_create_surface(display->compositor);
++ display->cursor_surface =
++ wl_compositor_create_surface(display->compositor);
++
++ if (display->shell) {
++ window->xdg_surface =
++ zxdg_shell_v6_get_xdg_surface(display->shell,
++ window->surface);
++
++ assert(window->xdg_surface);
++
++ zxdg_surface_v6_add_listener(window->xdg_surface,
++ &xdg_surface_listener, window);
++
++ window->xdg_toplevel =
++ zxdg_surface_v6_get_toplevel(window->xdg_surface);
++ zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
++ &xdg_toplevel_listener, window);
++
++ zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-configure-mtk");
++ window->wait_for_configure = true;
++ wl_surface_commit(window->surface);
++ } else if (display->fshell) {
++ zwp_fullscreen_shell_v1_present_surface(display->fshell,
++ window->surface,
++ ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
++ NULL);
++ //} else if (display->ivi_application ) {
++ // uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
++ // window->ivi_surface =
++ // ivi_application_surface_create(display->ivi_application,
++ // id_ivisurf, window->surface);
++ // if (window->ivi_surface == NULL) {
++ // fprintf(stderr, "Failed to create ivi_client_surface\n");
++ // abort();
++ // }
++//
++ // ivi_surface_add_listener(window->ivi_surface,
++ // &ivi_surface_listener, window);
++
++ } else {
++ assert(0);
++ }
++
++}
++
++static void
++destroy_surface(struct window *window)
++{
++ if (window->xdg_toplevel)
++ zxdg_toplevel_v6_destroy(window->xdg_toplevel);
++ if (window->xdg_surface)
++ zxdg_surface_v6_destroy(window->xdg_surface);
++ //if (window->display->ivi_application)
++ // ivi_surface_destroy(window->ivi_surface);
++ if (window->display->fshell)
++ zwp_fullscreen_shell_v1_release(window->display->fshell);
++ wl_surface_destroy(window->surface);
++
++ if (window->callback)
++ wl_callback_destroy(window->callback);
++
++ if (window->image.out_bufs[0].buffer)
++ wl_buffer_destroy(window->image.out_bufs[0].buffer);
++ if (window->image.out_bufs[1].buffer)
++ wl_buffer_destroy(window->image.out_bufs[1].buffer);
++ if (window->image.out_bufs[2].buffer)
++ wl_buffer_destroy(window->image.out_bufs[2].buffer);
++}
++
++static const struct wl_callback_listener frame_listener;
++
++static void
++redraw(void *data, struct wl_callback *callback, uint32_t time)
++{
++ struct window *window = data;
++ struct buffer *buffer;
++ char filename[MAX_LEN] = {0};
++ static const uint32_t benchmark_interval = 5;
++ struct wl_region *region;
++ struct timeval tv;
++ int tmp;
++
++ buffer = window_next_buffer(window);
++ if (!buffer) {
++ fprintf(stderr,
++ !callback ? "error: Failed to create the first buffer.\n" :
++ "error: Both buffers busy at redraw(). Server bug?\n");
++ abort();
++ }
++
++ gettimeofday(&tv, NULL);
++ time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
++ if (window->frames == 0)
++ window->benchmark_time = time;
++ if (time - window->benchmark_time > (benchmark_interval * 1000)) {
++ printf("debug: %d frames in %d seconds: %f fps\n",
++ window->frames,
++ benchmark_interval,
++ (float) window->frames / benchmark_interval);
++ window->benchmark_time = time;
++ window->frames = 0;
++ }
++
++ if (window->opaque || window->fullscreen) {
++ region = wl_compositor_create_region(window->display->compositor);
++ wl_region_add(region, 0, 0,
++ window->geometry.width,
++ window->geometry.height);
++ wl_surface_set_opaque_region(window->surface, region);
++ wl_region_destroy(region);
++ } else {
++ wl_surface_set_opaque_region(window->surface, NULL);
++ }
++
++ wl_surface_attach(window->surface, buffer->buffer, 0, 0);
++ wl_surface_set_buffer_transform(window->surface,
++ window->transform);
++ wl_surface_damage(window->surface,
++ 0, 0, window->geometry.width, window->geometry.height);
++
++ if (callback)
++ wl_callback_destroy(callback);
++
++ window->callback = wl_surface_frame(window->surface);
++ wl_callback_add_listener(window->callback, &frame_listener, window);
++ wl_surface_commit(window->surface);
++ buffer->busy = 1;
++
++ window->frames++;
++}
++
++static const struct wl_callback_listener frame_listener = {
++ redraw
++};
++
++static void
++pointer_handle_enter(void *data, struct wl_pointer *pointer,
++ uint32_t serial, struct wl_surface *surface,
++ wl_fixed_t sx, wl_fixed_t sy)
++{
++ struct display *display = data;
++ struct wl_buffer *buffer;
++ struct wl_cursor *cursor = display->default_cursor;
++ struct wl_cursor_image *image;
++
++ if (display->window->fullscreen)
++ wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
++ else if (cursor) {
++ image = display->default_cursor->images[0];
++ buffer = wl_cursor_image_get_buffer(image);
++ if (!buffer)
++ return;
++ wl_pointer_set_cursor(pointer, serial,
++ display->cursor_surface,
++ image->hotspot_x,
++ image->hotspot_y);
++ wl_surface_attach(display->cursor_surface, buffer, 0, 0);
++ wl_surface_damage(display->cursor_surface, 0, 0,
++ image->width, image->height);
++ wl_surface_commit(display->cursor_surface);
++ }
++
++}
++
++static void
++pointer_handle_leave(void *data, struct wl_pointer *pointer,
++ uint32_t serial, struct wl_surface *surface)
++{
++}
++
++static void
++pointer_handle_motion(void *data, struct wl_pointer *pointer,
++ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
++{
++
++}
++
++static void
++pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
++ uint32_t serial, uint32_t time, uint32_t button,
++ uint32_t state)
++{
++ struct display *display = data;
++
++ if (!display->window->xdg_surface)
++ return;
++
++ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
++ zxdg_toplevel_v6_move(display->window->xdg_toplevel,
++ display->seat, serial);
++}
++
++static void
++pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
++ uint32_t time, uint32_t axis, wl_fixed_t value)
++{
++}
++
++static const struct wl_pointer_listener pointer_listener = {
++ pointer_handle_enter,
++ pointer_handle_leave,
++ pointer_handle_motion,
++ pointer_handle_button,
++ pointer_handle_axis,
++};
++
++static void
++touch_handle_down(void *data, struct wl_touch *wl_touch,
++ uint32_t serial, uint32_t time, struct wl_surface *surface,
++ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
++{
++ struct display *d = (struct display *)data;
++
++ if (!d->shell)
++ return;
++
++ zxdg_toplevel_v6_move(d->window->xdg_toplevel, d->seat, serial);
++}
++
++static void
++touch_handle_up(void *data, struct wl_touch *wl_touch,
++ uint32_t serial, uint32_t time, int32_t id)
++{
++}
++
++static void
++touch_handle_motion(void *data, struct wl_touch *wl_touch,
++ uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
++{
++}
++
++static void
++touch_handle_frame(void *data, struct wl_touch *wl_touch)
++{
++}
++
++static void
++touch_handle_cancel(void *data, struct wl_touch *wl_touch)
++{
++}
++
++static const struct wl_touch_listener touch_listener = {
++ touch_handle_down,
++ touch_handle_up,
++ touch_handle_motion,
++ touch_handle_frame,
++ touch_handle_cancel,
++};
++
++static void
++keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
++ uint32_t format, int fd, uint32_t size)
++{
++}
++
++static void
++keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, struct wl_surface *surface,
++ struct wl_array *keys)
++{
++}
++
++static void
++keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, struct wl_surface *surface)
++{
++}
++
++static void
++keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, uint32_t time, uint32_t key,
++ uint32_t state)
++{
++ struct display *d = data;
++
++ if (!d->shell)
++ return;
++
++ if (key == KEY_F11 && state) {
++ if (d->window->fullscreen)
++ zxdg_toplevel_v6_unset_fullscreen(d->window->xdg_toplevel);
++ else
++ zxdg_toplevel_v6_set_fullscreen(d->window->xdg_toplevel, NULL);
++ } else if (key == KEY_ESC && state)
++ running = 0;
++}
++
++static void
++keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
++ uint32_t serial, uint32_t mods_depressed,
++ uint32_t mods_latched, uint32_t mods_locked,
++ uint32_t group)
++{
++}
++
++static const struct wl_keyboard_listener keyboard_listener = {
++ keyboard_handle_keymap,
++ keyboard_handle_enter,
++ keyboard_handle_leave,
++ keyboard_handle_key,
++ keyboard_handle_modifiers,
++};
++
++static void
++seat_handle_capabilities(void *data, struct wl_seat *seat,
++ enum wl_seat_capability caps)
++{
++ struct display *d = data;
++
++ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
++ d->pointer = wl_seat_get_pointer(seat);
++ wl_pointer_add_listener(d->pointer, &pointer_listener, d);
++ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
++ wl_pointer_destroy(d->pointer);
++ d->pointer = NULL;
++ }
++
++ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
++ d->keyboard = wl_seat_get_keyboard(seat);
++ wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
++ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) {
++ wl_keyboard_destroy(d->keyboard);
++ d->keyboard = NULL;
++ }
++
++ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !d->touch) {
++ d->touch = wl_seat_get_touch(seat);
++ wl_touch_set_user_data(d->touch, d);
++ wl_touch_add_listener(d->touch, &touch_listener, d);
++ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && d->touch) {
++ wl_touch_destroy(d->touch);
++ d->touch = NULL;
++ }
++}
++
++static const struct wl_seat_listener seat_listener = {
++ seat_handle_capabilities,
++};
++
++
++static void
++xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
++{
++ zxdg_shell_v6_pong(shell, serial);
++}
++
++static const struct zxdg_shell_v6_listener xdg_shell_listener = {
++ xdg_shell_ping,
++};
++
++static void
++dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format)
++{
++ fprintf(stderr, "debug: Support drm_format 0x%x \n", format);
++}
++
++static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
++ dmabuf_format
++};
++
++static void
++registry_handle_global(void *data, struct wl_registry *registry,
++ uint32_t name, const char *interface, uint32_t version)
++{
++ struct display *d = data;
++
++ if (strcmp(interface, "wl_compositor") == 0) {
++ d->compositor =
++ wl_registry_bind(registry, name,
++ &wl_compositor_interface, 2);
++ } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
++ d->shell = wl_registry_bind(registry, name,
++ &zxdg_shell_v6_interface, 1);
++ zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
++ } else if (strcmp(interface, "wl_seat") == 0) {
++ d->seat = wl_registry_bind(registry, name,
++ &wl_seat_interface, 1);
++ wl_seat_add_listener(d->seat, &seat_listener, d);
++ } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
++ d->fshell = wl_registry_bind(registry, name,
++ &zwp_fullscreen_shell_v1_interface, 1);
++ } else if (strcmp(interface, "wl_shm") == 0) {
++ d->shm = wl_registry_bind(registry, name,
++ &wl_shm_interface, 1);
++ d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
++ if (!d->cursor_theme) {
++ fprintf(stderr, "unable to load default theme\n");
++ return;
++ }
++ d->default_cursor =
++ wl_cursor_theme_get_cursor(d->cursor_theme, "grabbing");
++ if (!d->default_cursor) {
++ fprintf(stderr, "unable to load default grabbing pointer\n");
++ // TODO: abort ?
++ }
++ //} else if (strcmp(interface, "ivi_application") == 0) {
++ // d->ivi_application =
++ // wl_registry_bind(registry, name,
++ // &ivi_application_interface, 1);
++ } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
++ d->dmabuf = wl_registry_bind(registry, name,
++ &zwp_linux_dmabuf_v1_interface, 1);
++ zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
++ }
++}
++
++static void
++registry_handle_global_remove(void *data, struct wl_registry *registry,
++ uint32_t name)
++{
++}
++
++static const struct wl_registry_listener registry_listener = {
++ registry_handle_global,
++ registry_handle_global_remove
++};
++
++static void
++destroy_display(struct display *display)
++{
++ if (display->dmabuf)
++ zwp_linux_dmabuf_v1_destroy(display->dmabuf);
++
++ if (display->shell)
++ zxdg_shell_v6_destroy(display->shell);
++
++ if (display->fshell)
++ zwp_fullscreen_shell_v1_release(display->fshell);
++
++ if (display->compositor)
++ wl_compositor_destroy(display->compositor);
++
++ wl_surface_destroy(display->cursor_surface);
++ if (display->cursor_theme)
++ wl_cursor_theme_destroy(display->cursor_theme);
++
++ //if (display->ivi_application)
++ // ivi_application_destroy(display->ivi_application);
++
++ wl_registry_destroy(display->registry);
++ wl_display_flush(display->display);
++ wl_display_disconnect(display->display);
++ free(display);
++}
++
++static struct display *
++create_display(struct window *window)
++{
++ struct display *display;
++
++ display = malloc(sizeof *display);
++ if (display == NULL) {
++ fprintf(stderr, "out of memory\n");
++ exit(1);
++ }
++ display->display = wl_display_connect(NULL);
++ assert(display->display);
++ display->window = window;
++
++ display->registry = wl_display_get_registry(display->display);
++ wl_registry_add_listener(display->registry,
++ ®istry_listener, display);
++ wl_display_roundtrip(display->display);
++ if (display->dmabuf == NULL) {
++ fprintf(stderr, "No zwp_linux_dmabuf_v1 global found\n");
++ exit(1);
++ }
++ wl_display_roundtrip(display->display);
++
++ return display;
++}
++
++static void
++signal_int(int signum)
++{
++ running = 0;
++}
++
++/*
++ * parse the message inputed for rawdata
++ * egg: -F /usr/share/weston/rawdata.nv16:720x480@5
++ * filename:widthxheight@format
++*/
++static int parse_file(struct file_arg *file, char *p)
++{
++ char *end;
++ char *pPos = p;
++ int len, i;
++
++ len = strlen(pPos) + 1;
++ for (i = 0; i < len; i++)
++ if(pPos[i] == ':')
++ pPos[i] = '\0';
++
++ memcpy(file->filename, pPos, strlen(pPos) + 1);
++ pPos = pPos + strlen(pPos) + 1;
++ file->width = strtoul(pPos, &end, 10);
++ if (*end != 'x')
++ return -EINVAL;
++ pPos = end + 1;
++ file->height = strtoul(pPos, &end, 10);
++ if (*end != '@')
++ return -EINVAL;
++ pPos = end + 1;
++ file->format = strtoul(pPos, &end, 10);
++ if (*end != '\0')
++ return -EINVAL;
++ return 0;
++}
++
++static void init_window(struct window *window)
++{
++ window->geometry.width = 0;
++ window->geometry.height = 0;
++ window->buffer_size = 32;
++ window->transform = WL_OUTPUT_TRANSFORM_NORMAL;
++ window->opaque = 1;
++ window->overlay = 0;
++ window->format = 0;
++ window->drm_card_fd = -1;
++}
++
++static void
++usage(int error_code)
++{
++ fprintf(stderr, "Usage: mtkdraw-dma [OPTIONS]\n\n"
++ " -f Run in fullscreen mode(only desktop-shell valid)\n"
++ " -o Create an opaque surface\n"
++ " -s Use a 16 bpp EGL config\n"
++ " -t Set display buffer transform(0~7)\n"
++ " -F rawdata message(rawdata size provided is 320x480)\n"
++ " eg:-F /usr/share/weston/rawdata.nv16:320x480@5\n"
++ " @14 stand for nv16 format, formats supported as follows\n"
++ " now only support 8 formats\n"
++ " 0 --> IMG_FORMAT_RGB565\n"
++ " 1 --> IMG_FORMAT_XRGB8888\n"
++ " 2 --> IMG_FORMAT_ARGB8888\n"
++ " 3 --> IMG_FORMAT_YUYV\n"
++ " 4 --> IMG_FORMAT_NV12\n"
++ " 5 --> IMG_FORMAT_NV16\n"
++ " 6 --> IMG_FORMAT_YUV420\n"
++ " 7 --> IMG_FORMAT_YVU420\n"
++ " -d Enable debug output\n"
++ " -overlay Enable overlay switch\n"
++ " -h This help text\n\n");
++
++ exit(error_code);
++}
++
++int
++main(int argc, char **argv)
++{
++ struct sigaction sigint;
++ struct display *display;
++ struct window window = { 0 };
++ int i, ret = 0;
++ struct file_arg *file;
++
++ init_window(&window);
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp("-f", argv[i]) == 0)
++ window.fullscreen = 1;
++ else if (strcmp("-o", argv[i]) == 0)
++ window.opaque = 0;
++ else if (strcmp("-s", argv[i]) == 0)
++ window.buffer_size = 16;
++ else if (strcmp("-t", argv[i]) == 0)
++ window.transform = atoi(argv[++i]);
++ else if (strcmp("-F", argv[i]) == 0){
++ ret = parse_file(&window.image.fProp, argv[++i]);
++ if (ret < 0)
++ fprintf(stderr, "error: input error, like: -F "
++ "/usr/share/weston/rawdata.nv16:320x480@5\n");
++ }
++ else if (strcmp("-d", argv[i]) == 0)
++ debug = 1;
++ else if (strcmp("-overlay", argv[i]) == 0)
++ window.overlay = 1;
++ else if (strcmp("-h", argv[i]) == 0)
++ usage(EXIT_SUCCESS);
++ else
++ usage(EXIT_FAILURE);
++ }
++
++ file = &window.image.fProp;
++ if((file->width == 0) || (file->height ==0) || (file->filename == 0))
++ {
++ /*default sample*/
++ file->width = 320;
++ file->height = 480;
++ file->format = IMG_FORMAT_NV16;
++ snprintf(file->filename, MAX_LEN, "/usr/share/weston/rawdata.nv16");
++ fprintf(stderr, "debug: You have choose the default example!\n");
++ }
++
++ fprintf(stderr, "debug: The file is %s width/height/format[%d %d %d]\n",
++ file->filename, file->width, file->height, file->format);
++
++ window.geometry.width = file->width;
++ window.geometry.height = file->height;
++ window.window_size = window.geometry;
++
++ display = create_display(&window);
++ window.display = display;
++ //display->window = &window;
++
++ create_surface(&window);
++
++ ret = init_img_texture(&window);
++ if (ret < 0){
++ fprintf(stderr, "error: init_img_texture failed\n");
++ return -1;
++ }
++
++ window.drm_card_fd = _kms_device_fd();
++ if (window.drm_card_fd < 0) {
++ fprintf(stderr, "error: fail to get drm_card_fd !\n");
++ return -1;
++ }
++
++ sigint.sa_handler = signal_int;
++ sigemptyset(&sigint.sa_mask);
++ sigint.sa_flags = SA_RESETHAND;
++ sigaction(SIGINT, &sigint, NULL);
++
++ if (!window.wait_for_configure)
++ redraw(&window, NULL, 0);
++
++ while (running && ret != -1)
++ ret = wl_display_dispatch(display->display);
++
++ fprintf(stderr, "debug: simple-configure-mtk exiting\n");
++ destroy_surface(&window);
++ destroy_display(display);
++
++ return 0;
++}
++
++
+diff --git a/configure.ac b/configure.ac
+index 8b3e17e..e4bf195 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -411,6 +411,7 @@ if ! test "x$enable_simple_dmabuf_v4l_client" = "xno"; then
+ enable_simple_dmabuf_v4l_client="$have_simple_dmabuf_v4l_client"
+ fi
+ AM_CONDITIONAL(BUILD_SIMPLE_DMABUF_V4L_CLIENT, test "x$enable_simple_dmabuf_v4l_client" = "xyes")
++AM_CONDITIONAL(BUILD_SIMPLE_CONFIGURE_MTK_CLIENT, test "x$enable_simple_dmabuf_v4l_client" = "xyes")
+
+ AC_ARG_ENABLE(clients, [ --enable-clients],, enable_clients=yes)
+ AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0009-weston-add-surface-overlay-assignment-interface.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0009-weston-add-surface-overlay-assignment-interface.patch
new file mode 100644
index 0000000..a1bfe8c
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0009-weston-add-surface-overlay-assignment-interface.patch
@@ -0,0 +1,417 @@
+From 5fdbcf3ea4b5f81b4aa7a03ff2bd130a6bb2a022 Mon Sep 17 00:00:00 2001
+From: Jia Rong <jia.rong@mediatek.com>
+Date: Thu, 3 May 2018 09:06:15 +0800
+Subject: [PATCH] weston: add surface overlay assignment interface
+
+add surface overlay assignment interface
+Test: OK
+
+Change-Id: I970797b6c3fe59567590639c2fe1e65784f296aa
+Signed-off-by: Jia Rong <jia.rong@mediatek.com>
+CR-Id: AUTO00016576
+---
+ Makefile.am | 6 +-
+ clients/simple-configure-mtk.c | 17 +++++
+ compositor/main.c | 6 ++
+ libweston/compositor-drm.c | 6 ++
+ libweston/compositor.h | 12 ++++
+ libweston/weston-configure-mtk.c | 126 ++++++++++++++++++++++++++++++++++++++
+ libweston/weston-configure-mtk.h | 54 ++++++++++++++++
+ protocol/weston-configure-mtk.xml | 30 +++++++++
+ 8 files changed, 256 insertions(+), 1 deletion(-)
+ create mode 100644 libweston/weston-configure-mtk.c
+ create mode 100644 libweston/weston-configure-mtk.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 576b4a1..cf92198 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -108,6 +108,8 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
+ libweston/pixel-formats.c \
+ libweston/pixel-formats.h \
+ libweston/weston-screenshooter-mtk.c \
++ libweston/weston-configure-mtk.c \
++ libweston/weston-configure-mtk.h \
+ shared/helpers.h \
+ shared/matrix.c \
+ shared/matrix.h \
+@@ -666,7 +668,9 @@ nodist_weston_simple_configure_mtk_SOURCES = \
+ protocol/fullscreen-shell-unstable-v1-protocol.c \
+ protocol/fullscreen-shell-unstable-v1-client-protocol.h \
+ protocol/linux-dmabuf-unstable-v1-protocol.c \
+- protocol/linux-dmabuf-unstable-v1-client-protocol.h
++ protocol/linux-dmabuf-unstable-v1-client-protocol.h \
++ protocol/weston-configure-mtk-protocol.c \
++ protocol/weston-configure-mtk-client-protocol.h
+ weston_simple_configure_mtk_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+ weston_simple_configure_mtk_LDADD = $(EGL_LIBS) $(LIBDRM_LIBS) libtoytoolkit.la
+ BUILT_SOURCES += protocol/linux-dmabuf-unstable-v1-client-protocol.h
+diff --git a/clients/simple-configure-mtk.c b/clients/simple-configure-mtk.c
+index f94497e..8b146ff 100644
+--- a/clients/simple-configure-mtk.c
++++ b/clients/simple-configure-mtk.c
+@@ -24,6 +24,7 @@
+ #include "xdg-shell-unstable-v6-client-protocol.h"
+ #include "linux-dmabuf-unstable-v1-client-protocol.h"
+ #include "fullscreen-shell-unstable-v1-client-protocol.h"
++#include "weston-configure-mtk-client-protocol.h"
+
+ #include <shared/platform.h>
+
+@@ -55,6 +56,7 @@ struct display {
+ struct wl_cursor *default_cursor;
+ struct wl_surface *cursor_surface;
+ struct window *window;
++ struct config_switch *config_switch;
+ };
+
+ struct geometry {
+@@ -92,6 +94,7 @@ struct window {
+ int fullscreen, opaque, buffer_size, overlay, format;
+ enum wl_output_transform transform;
+ int drm_card_fd;
++ struct config_switch_set *switch_set;
+ };
+
+ struct img_texture {
+@@ -591,6 +594,8 @@ create_surface(struct window *window)
+ display->cursor_surface =
+ wl_compositor_create_surface(display->compositor);
+
++ window->switch_set = config_switch_connect(display->config_switch, window->surface);
++
+ if (display->shell) {
+ window->xdg_surface =
+ zxdg_shell_v6_get_xdg_surface(display->shell,
+@@ -991,6 +996,10 @@ registry_handle_global(void *data, struct wl_registry *registry,
+ d->dmabuf = wl_registry_bind(registry, name,
+ &zwp_linux_dmabuf_v1_interface, 1);
+ zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
++ } else if (strcmp(interface, "config_switch") == 0) {
++ d->config_switch =
++ wl_registry_bind(registry, name,
++ &config_switch_interface, 1);
+ }
+ }
+
+@@ -1208,6 +1217,14 @@ main(int argc, char **argv)
+ fprintf(stderr, "error: fail to get drm_card_fd !\n");
+ return -1;
+ }
++ /*
++ * setting sprite_switch = 0, indicate not walk overlay
++ * setting sprite_switch = 1, indicate walk overlay
++ */
++ if(window.overlay)
++ config_switch_set_sprite_switch(window.switch_set, 1);
++ else
++ config_switch_set_sprite_switch(window.switch_set, 0);
+
+ sigint.sa_handler = signal_int;
+ sigemptyset(&sigint.sa_mask);
+diff --git a/compositor/main.c b/compositor/main.c
+index 72c3cd1..5a8fd55 100644
+--- a/compositor/main.c
++++ b/compositor/main.c
+@@ -56,6 +56,7 @@
+ #include "git-version.h"
+ #include "version.h"
+ #include "weston.h"
++#include "../libweston/weston-configure-mtk.h"
+
+ #include "compositor-drm.h"
+ #include "compositor-headless.h"
+@@ -1879,6 +1880,11 @@ int main(int argc, char *argv[])
+
+ weston_pending_output_coldplug(ec);
+
++ if (config_switch_global_create(ec) < 0) {
++ weston_log("fatal: failed to config_switch_global_create\n");
++ goto out;
++ }
++
+ catch_signals();
+ segv_compositor = ec;
+
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index 064d8c2..b5b103b 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -2753,6 +2753,12 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state,
+ uint32_t format;
+ wl_fixed_t sx1, sy1, sx2, sy2;
+
++ /*
++ * if switch controlled by client is off, then return.
++ */
++ if ((!ev->surface->config_switch)||(!ev->surface->config_switch->sprites_switch))
++ return NULL;
++
+ if (b->sprites_are_broken)
+ return NULL;
+
+diff --git a/libweston/compositor.h b/libweston/compositor.h
+index dea88dc..6470173 100644
+--- a/libweston/compositor.h
++++ b/libweston/compositor.h
+@@ -1141,6 +1141,16 @@ struct weston_surface_state {
+ struct weston_buffer_viewport buffer_viewport;
+ };
+
++/*
++ * For setting whether the views on this surface walk
++ * overlay path; on==>1, off==>0
++*/
++struct config_switch{
++ struct wl_resource *resource;
++ void *private;
++ int sprites_switch;
++};
++
+ struct weston_surface_activation_data {
+ struct weston_surface *surface;
+ struct weston_seat *seat;
+@@ -1262,6 +1272,8 @@ struct weston_surface {
+
+ /* An list of per seat pointer constraints. */
+ struct wl_list pointer_constraints;
++
++ struct config_switch *config_switch;
+ };
+
+ struct weston_subsurface {
+diff --git a/libweston/weston-configure-mtk.c b/libweston/weston-configure-mtk.c
+new file mode 100644
+index 0000000..185f91c
+--- /dev/null
++++ b/libweston/weston-configure-mtk.c
+@@ -0,0 +1,126 @@
++#include "config.h"
++#include <fcntl.h>
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <limits.h>
++#include <stdarg.h>
++#include <assert.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++#include <sys/wait.h>
++#include <sys/socket.h>
++#include <sys/utsname.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <math.h>
++#include <linux/input.h>
++#include <dlfcn.h>
++#include <signal.h>
++#include <setjmp.h>
++#include <sys/time.h>
++#include <time.h>
++#include <errno.h>
++
++#include "timeline.h"
++
++#include "compositor.h"
++//#include "scaler-server-protocol.h"
++#include "shared/helpers.h"
++#include "shared/os-compatibility.h"
++#include "shared/timespec-util.h"
++#include "git-version.h"
++#include "version.h"
++
++#include "weston-configure-mtk.h"
++#include "weston-configure-mtk-server-protocol.h"
++
++static void
++config_set_sprite_switch(struct wl_client *client,
++ struct wl_resource *resource,
++ int32_t spr_switch)
++{
++ struct config_switch *configure = wl_resource_get_user_data(resource);
++
++ configure->sprites_switch = spr_switch;
++}
++
++static const struct config_switch_set_interface switch_set_interface = {
++ config_set_sprite_switch,
++};
++
++static struct config_switch *
++config_interface_create(struct weston_surface *surface)
++{
++ struct config_switch *config_switch;
++
++ config_switch = zalloc(sizeof *config_switch);
++ if (config_switch == NULL)
++ return NULL;
++
++ config_switch->private = (void *)surface;
++ surface->config_switch = config_switch;
++
++ return config_switch;
++}
++
++static void
++config_switch_connect(struct wl_client *client, struct wl_resource *resource,
++ struct wl_resource *wl_surface, uint32_t id)
++{
++ struct config_switch *config_switch = wl_resource_get_user_data(resource);
++ struct weston_surface *surface = wl_resource_get_user_data(wl_surface);
++
++ config_switch = config_interface_create(surface);
++ if (config_switch == NULL) {
++ wl_resource_post_no_memory(resource);
++ return;
++ }
++
++ config_switch->resource =
++ wl_resource_create(client, &config_switch_set_interface,
++ wl_resource_get_version(resource), id);
++ if (config_switch->resource == NULL) {
++ wl_resource_post_no_memory(resource);
++ return;
++ }
++ wl_resource_set_implementation(config_switch->resource, &switch_set_interface,
++ config_switch, NULL);
++}
++
++static const struct config_switch_interface switch_interface = {
++ config_switch_connect,
++};
++
++static void
++bind_config_switch(struct wl_client *client,
++ void *data, uint32_t version, uint32_t id)
++{
++ struct weston_compositor *compositor = data;
++ struct wl_resource *resource;
++
++ resource = wl_resource_create(client, &config_switch_interface,
++ MIN(version, 1), id);
++ if (resource == NULL) {
++ wl_client_post_no_memory(client);
++ return;
++ }
++
++ wl_resource_set_implementation(resource, &switch_interface,
++ compositor, NULL);
++}
++
++WL_EXPORT int
++config_switch_global_create(struct weston_compositor *ec)
++{
++ if(!ec)
++ return -1;
++ if (!wl_global_create(ec->wl_display, &config_switch_interface, 1,
++ ec, bind_config_switch)){
++ fprintf(stderr, "error: failed to config_switch_global_create: %s\n", dlerror());
++ return -1;
++ }
++ return 0;
++}
++
+diff --git a/libweston/weston-configure-mtk.h b/libweston/weston-configure-mtk.h
+new file mode 100644
+index 0000000..0f093fe
+--- /dev/null
++++ b/libweston/weston-configure-mtk.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright © 2008-2011 Kristian Høgsberg
++ * Copyright © 2012 Collabora, Ltd.
++ *
++ * 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 _APP_CONFIGURE_EXTENSION_H_
++#define _APP_CONFIGURE_EXTENSION_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stdbool.h>
++#include <time.h>
++#include <pixman.h>
++#include <xkbcommon/xkbcommon.h>
++
++#include <wayland-server.h>
++
++#include "version.h"
++#include "matrix.h"
++#include "config-parser.h"
++#include "zalloc.h"
++#include "timeline-object.h"
++
++int config_switch_global_create(struct weston_compositor *ec);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
++
+diff --git a/protocol/weston-configure-mtk.xml b/protocol/weston-configure-mtk.xml
+index e19a2ad..120e904 100644
+--- a/protocol/weston-configure-mtk.xml
++++ b/protocol/weston-configure-mtk.xml
+@@ -33,5 +33,35 @@
+ </event>
+ </interface>
+
++ <interface name="config_switch_set" version="1">
++ <description summary="app interface for setting configure for the surface"/>
++
++ <request name="sprite_switch">
++ <description summary="setting the surface configure">
++ This set view matched with the surface to show in overlay plane if
++ overlay planes are available.Otherwise, it walk primary plane to
++ render, and then send to drm to show.
++ </description>
++ <arg name="sprite_switch" type="int"/>
++ </request>
++ </interface>
++
++ <interface name="config_switch" version="1">
++ <description summary="create app configure path for setting parameter">
++ This interface is exposed as a global singleton.
++ This interface is implemented by server, it mainly provide channel to allow
++ client to control some properties.
++ </description>
++
++ <request name="connect">
++ <description summary="connect to server for setting parameter">
++ This request gives client way to connect server.In fact, parameters set by
++ app all through wl_surface because this is only way can be transmit by app.
++ </description>
++ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
++ <arg name="id" type="new_id" interface="config_switch_set"/>
++ </request>
++ </interface>
++
+ </protocol>
+
+--
+1.9.1
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/0010-add-writeback-connector-CAP.patch b/meta/meta-mediatek/recipes-graphics/wayland/weston/0010-add-writeback-connector-CAP.patch
new file mode 100644
index 0000000..ac9c8f4
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/0010-add-writeback-connector-CAP.patch
@@ -0,0 +1,49 @@
+From a4fb658b7d34df3c28a2066b238d8009640e50a7 Mon Sep 17 00:00:00 2001
+From: Ye Huang <ye.huang@mediatek.com>
+Date: Sun, 1 Sep 2019 23:03:44 +0800
+Subject: [PATCH] add-writeback-connector-CAP
+
+---
+ libweston/compositor-drm.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
+index fcc3307..cad2478 100644
+--- a/libweston/compositor-drm.c
++++ b/libweston/compositor-drm.c
+@@ -76,6 +76,10 @@
+ #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
+ #endif
+
++#ifndef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
++#define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5
++#endif
++
+ #ifndef DRM_CAP_CURSOR_WIDTH
+ #define DRM_CAP_CURSOR_WIDTH 0x8
+ #endif
+@@ -266,6 +270,7 @@ struct drm_backend {
+
+ bool universal_planes;
+ bool atomic_modeset;
++ bool wb_connector;
+
+ int use_pixman;
+
+@@ -3577,6 +3582,13 @@ init_kms_caps(struct drm_backend *b)
+ weston_log("DRM: %s atomic modesetting\n",
+ b->atomic_modeset ? "supports" : "does not support");
+
++ if (!getenv("DRM_CLIENT_CAP_WRITEBACK_CONNECTORS")) {
++ ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
++ b->wb_connector = (ret == 0);
++ }
++ weston_log("DRM: %s writeback connectors\n",
++ b->wb_connector ? "supports" : "does not support");
++
+ return 0;
+ }
+
+--
+2.23.0
+
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.argb b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.argb
new file mode 100644
index 0000000..a55fa0e
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.argb
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.nv12 b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.nv12
new file mode 100644
index 0000000..cc9fb1f
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.nv12
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.nv16 b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.nv16
new file mode 100644
index 0000000..3261abd
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.nv16
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.rgb565 b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.rgb565
new file mode 100644
index 0000000..21006dc
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.rgb565
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.xrgb b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.xrgb
new file mode 100644
index 0000000..a55fa0e
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.xrgb
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yu12 b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yu12
new file mode 100644
index 0000000..bab225d
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yu12
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yuyv b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yuyv
new file mode 100644
index 0000000..207ec59
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yuyv
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yv12 b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yv12
new file mode 100644
index 0000000..7a21d02
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdata.yv12
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdatatest.argb b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdatatest.argb
new file mode 100644
index 0000000..515fb66
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/rawdatatest.argb
Binary files differ
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/weston.service b/meta/meta-mediatek/recipes-graphics/wayland/weston/weston.service
new file mode 100644
index 0000000..3c9f4a8
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/weston.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Weston reference Wayland compositor
+After=dbus.service rc.pvr.service
+
+[Service]
+ExecStart=/usr/bin/weston-launch -u root -- --idle-time=4294967 --tty=1
+ExecStop=/usr/bin/killall -s KILL weston
+Type=simple
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston/weston.sh b/meta/meta-mediatek/recipes-graphics/wayland/weston/weston.sh
new file mode 100644
index 0000000..225a034
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston/weston.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if test -z "$XDG_RUNTIME_DIR"; then
+ export XDG_RUNTIME_DIR=/run/user/$UID
+ mkdir --parents $XDG_RUNTIME_DIR
+ chmod 0700 $XDG_RUNTIME_DIR
+fi
diff --git a/meta/meta-mediatek/recipes-graphics/wayland/weston_5.0.0.bbappend b/meta/meta-mediatek/recipes-graphics/wayland/weston_5.0.0.bbappend
new file mode 100644
index 0000000..5253869
--- /dev/null
+++ b/meta/meta-mediatek/recipes-graphics/wayland/weston_5.0.0.bbappend
@@ -0,0 +1,45 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+SRC_URI_append = " \
+ file://0001-PATCH-1-9-hmi-controller-use-output_w-h-instead-of-c.patch \
+ file://0003-PATCH-3-9-compose-engine-turn-to-pixman-if-gl-init-f.patch \
+ file://0004-PATCH-4-9-weston-do-not-check-master-fd-for-DRM-driv.patch \
+ file://0005-PATCH-5-9-weston-install-client-protocol-to-sysroot-.patch \
+ file://0006-PATCH-7-9-weston-screen-shot-add-screen-shot.patch \
+ file://0007-PATCH-weston-add-mtk-test-client.patch \
+ file://0008-PATCH-weston-add-surface-overlay-assignment-interfac.patch \
+ file://0001-add-switch_config.patch \
+ file://rawdata.argb \
+ file://rawdata.nv12 \
+ file://rawdata.nv16 \
+ file://rawdata.rgb565 \
+ file://rawdata.xrgb \
+ file://rawdata.yu12 \
+ file://rawdata.yuyv \
+ file://rawdata.yv12 \
+ file://rawdatatest.argb \
+"
+
+DEPENDS += "libdrm"
+FILES_${PN} += "${bindir}/* ${libdir}/weston/* ${sysconfdir}/xdg"
+FILES_${PN}-dbg += "${libdir}/weston/.debug/*"
+
+do_compile() {
+ oe_runmake \
+ CFLAGS+="-I${STAGING_INCDIR}/libdrm"
+}
+do_install_append() {
+ install -d ${D}/usr/share/weston/
+ cp ${WORKDIR}/rawdata* ${D}/usr/share/weston/
+
+ WESTON_INI_CONFIG=${sysconfdir}/xdg/weston
+ install -d ${D}${WESTON_INI_CONFIG}
+ echo "" >> ${D}${WESTON_INI_CONFIG}/weston.ini
+ echo "[output]" >> ${D}${WESTON_INI_CONFIG}/weston.ini
+ echo "name=DSI-1" >> ${D}${WESTON_INI_CONFIG}/weston.ini
+ if test "${DISPLAY_ORIENTATION}" != "";then
+ echo "transform=${DISPLAY_ORIENTATION}" >> ${D}${WESTON_INI_CONFIG}/weston.ini
+ else
+ echo "transform=90" >> ${D}${WESTON_INI_CONFIG}/weston.ini
+ fi
+}