--- /dev/null
+From f2025a7e8c178b8c52c2ca553459a7fea6caf5c8 Mon Sep 17 00:00:00 2001
+From: "yong.gan" <yong.gan@nxp.com>
+Date: Tue, 17 May 2016 09:10:50 +0800
+Subject: [PATCH 1/2] MGS-1783: xwld: Add clone mode support for multi display
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Support showing the same contents on multiple displays.
+Use the following command to enable multi-display:
+ openvt -v -- weston-launch -- --idle-time=0 --use-g2d=1 --device=/dev/fb0,/dev/fb4 --clone-mode --log=/var/log/weston.log
+
+Upstream-Status: Inappropriate [i.MX specific]
+Date: May 16, 2016
+Signed-off-by: Yong Gan <yong.gan@nxp.com>
+---
+ src/compositor-fbdev.c | 33 +++++++---
+ src/g2d-renderer.c | 171 ++++++++++++++++++++++++++++++++++++++++---------
+ src/g2d-renderer.h | 4 +-
+ 3 files changed, 167 insertions(+), 41 deletions(-)
+
+Index: weston-1.11.0/src/compositor-fbdev.c
+===================================================================
+--- weston-1.11.0.orig/src/compositor-fbdev.c 2016-10-06 13:17:41.738142236 -0500
++++ weston-1.11.0/src/compositor-fbdev.c 2016-10-06 13:28:22.000000000 -0500
+@@ -61,6 +61,8 @@
+ struct udev_input input;
+ int use_pixman;
+ int use_g2d;
++ int clone_mode;
++ char *clone_device;
+ uint32_t output_transform;
+ struct wl_listener session_listener;
+ #ifdef ENABLE_EGL
+@@ -525,12 +527,15 @@
+ if (pixman_renderer_output_create(&output->base) < 0)
+ goto out_hw_surface;
+ } else if(backend->use_g2d) {
++ const char *g2d_device = device;
++ if (backend->clone_mode)
++ g2d_device = backend->clone_device;
++
+ if (g2d_renderer->output_create(&output->base,
+- backend->compositor->wl_display, device) < 0) {
++ backend->compositor->wl_display, g2d_device) < 0) {
+ weston_log("g2d_renderer_output_create failed.\n");
+ goto out_hw_surface;
+ }
+-
+ } else {
+ #ifdef ENABLE_EGL
+ setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
+@@ -803,6 +808,8 @@
+ backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
+ backend->use_pixman = !(param->use_gl || param->use_g2d);
+ backend->use_g2d = param->use_g2d;
++ backend->clone_mode = param->clone_mode;
++ backend->clone_device = param->device;
+ backend->output_transform = param->output_transform;
+
+ weston_setup_vt_switch_bindings(compositor);
+@@ -844,16 +851,21 @@
+ displays[dispCount][k] = '\0';
+ dispCount++;
+
+- for(i=0; i<dispCount; i++)
+- {
+- if (fbdev_output_create(backend, x, y, displays[i]) < 0)
++ if(backend->clone_mode){
++ if (fbdev_output_create(backend, x, y, displays[0]) < 0)
+ goto out_launcher;
+- x += container_of(backend->compositor->output_list.prev,
+- struct weston_output,
+- link)->width;
++ }
++ else{
++ for(i= 0; i < dispCount; i++){
++ if (fbdev_output_create(backend, x, y, displays[i]) < 0)
++ goto out_launcher;
++ x += container_of(backend->compositor->output_list.prev,
++ struct weston_output,
++ link)->width;
++ }
+ }
+ }
+- else {
++ else {
+ #ifdef ENABLE_EGL
+ gl_renderer = weston_load_module("gl-renderer.so",
+ "gl_renderer_interface");
+Index: weston-1.11.0/src/g2d-renderer.c
+===================================================================
+--- weston-1.11.0.orig/src/g2d-renderer.c 2016-10-06 13:17:41.738142236 -0500
++++ weston-1.11.0/src/g2d-renderer.c 2016-10-06 13:17:41.734142216 -0500
+@@ -37,15 +37,16 @@
+ #include <sys/ioctl.h>
+ #include <fcntl.h>
+ #include <unistd.h>
++#include <g2dExt.h>
++#include <HAL/gc_hal_eglplatform.h>
+
+ #include "compositor.h"
+ #include "g2d-renderer.h"
+ #include "vertex-clipping.h"
+ #include "shared/helpers.h"
+-#include "HAL/gc_hal_eglplatform.h"
+-#include "g2dExt.h"
+
+ #define BUFFER_DAMAGE_COUNT 2
++extern struct wl_global* gcoOS_WaylandCreateVivGlobal(struct wl_display* display);
+
+ typedef struct _g2dRECT
+ {
+@@ -63,6 +64,7 @@
+ size_t buffer_length; /* length of frame buffer memory in bytes */
+ size_t physical;
+ enum g2d_format pixel_format; /* frame buffer pixel format */
++ int fb_fd;
+ };
+
+ struct g2d_output_state {
+@@ -74,10 +76,12 @@
+ struct g2d_surfaceEx offscreenSurface;
+ struct g2d_buf *offscreen_buf;
+ struct fb_screeninfo fb_info;
++ struct fb_screeninfo *mirror_fb_info;
++ struct g2d_surfaceEx *mirrorSurf;
+ int directBlit;
++ int clone_display_num;
+ int width;
+ int height;
+- int fb_fd;
+ };
+
+ struct g2d_surface_state {
+@@ -366,7 +370,7 @@
+ struct g2d_output_state *go = get_output_state(output);
+ go->fb_info.varinfo.yoffset = go->activebuffer * go->fb_info.y_resolution;
+
+- if(ioctl(go->fb_fd, FBIOPAN_DISPLAY, &(go->fb_info.varinfo)) < 0)
++ if(ioctl(go->fb_info.fb_fd, FBIOPAN_DISPLAY, &(go->fb_info.varinfo)) < 0)
+ {
+ weston_log("FBIOPAN_DISPLAY Failed\n");
+ }
+@@ -388,6 +392,28 @@
+ &go->renderSurf[go->activebuffer], &srcRect, &dstrect);
+ }
+
++ if(go->clone_display_num)
++ {
++ int i = 0;
++ for(i = 0; i < go->clone_display_num; i++)
++ {
++ g2dRECT srcRect = {0, 0, go->renderSurf[go->activebuffer].base.width, go->renderSurf[go->activebuffer].base.height};
++ g2dRECT dstrect = {0, 0, go->mirrorSurf[i].base.width, go->mirrorSurf[i].base.height};
++ g2dRECT clipRect = srcRect;
++ g2d_set_clipping(gr->handle, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
++ if(go->directBlit || go->nNumBuffers > 1)
++ {
++ g2d_blitSurface(gr->handle, &go->renderSurf[go->activebuffer],
++ &go->mirrorSurf[i], &srcRect, &dstrect);
++ }
++ else
++ {
++ g2d_blitSurface(gr->handle, &go->offscreenSurface,
++ &go->mirrorSurf[i], &srcRect, &dstrect);
++ }
++ }
++ }
++
+ g2d_finish(gr->handle);
+
+ if(go->nNumBuffers > 1)
+@@ -940,10 +966,10 @@
+ go->offscreen_buf = NULL;
+ }
+
+- if(go->fb_fd)
++ if(go->fb_info.fb_fd)
+ {
+- close(go->fb_fd);
+- go->fb_fd = 0;
++ close(go->fb_info.fb_fd);
++ go->fb_info.fb_fd = 0;
+ }
+
+ if(go->renderSurf)
+@@ -951,6 +977,24 @@
+ free(go->renderSurf);
+ go->renderSurf = NULL;
+ }
++ for (i = 0; i < go->clone_display_num; i++)
++ {
++ if(go->mirror_fb_info[i].fb_fd)
++ {
++ close(go->mirror_fb_info[i].fb_fd);
++ go->mirror_fb_info[i].fb_fd = 0;
++ }
++ }
++ if(go->mirrorSurf)
++ {
++ free(go->mirrorSurf);
++ go->mirrorSurf = NULL;
++ }
++ if(go->mirror_fb_info)
++ {
++ free(go->mirror_fb_info);
++ go->mirror_fb_info = NULL;
++ }
+
+ free(go);
+ }
+@@ -1085,39 +1129,27 @@
+ struct fb_screeninfo *screen_info)
+ {
+ /* Open the frame buffer device. */
+- output->fb_fd = open(fb_dev, O_RDWR | O_CLOEXEC);
+- if (output->fb_fd < 0) {
++ screen_info->fb_fd = open(fb_dev, O_RDWR | O_CLOEXEC);
++ if (screen_info->fb_fd < 0) {
+ weston_log("Failed to open frame buffer device%s \n", fb_dev);
+ return -1;
+ }
+
+ /* Grab the screen info. */
+- if (fb_query_screen_info(output, output->fb_fd, screen_info) < 0) {
++ if (fb_query_screen_info(output, screen_info->fb_fd, screen_info) < 0) {
+ weston_log("Failed to get frame buffer info \n");
+
+- close(output->fb_fd);
++ close(screen_info->fb_fd);
+ return -1;
+ }
+
+ return 0;
+ }
+
+-static int
+-g2d_renderer_output_create(struct weston_output *output, struct wl_display *wl_display, const char *device)
+-
+- {
+- struct g2d_renderer *gr = get_renderer(output->compositor);
+- struct g2d_output_state *go;
+- int i = 0;
+- int offset = 0;
++static void
++getBufferNumber(struct g2d_output_state *go)
++{
+ char *p = NULL;
+- go = zalloc(sizeof *go);
+- if (go == NULL)
+- return -1;
+-
+- output->renderer_state = go;
+- gr->viv_global = gcoOS_WaylandCreateVivGlobal(wl_display);
+-
+ p = getenv("FB_MULTI_BUFFER");
+ if (p == gcvNULL)
+ {
+@@ -1126,7 +1158,7 @@
+ else
+ {
+ go->nNumBuffers = atoi(p);
+- if (go->nNumBuffers < 1)
++ if (go->nNumBuffers < 2)
+ {
+ go->nNumBuffers = 1;
+ }
+@@ -1137,13 +1169,19 @@
+ }
+ }
+ weston_log("FB_MULTI_BUFFER = %d\n", go->nNumBuffers);
++}
+
++static int
++g2d_renderer_surface_create(struct g2d_output_state *go, struct g2d_renderer *gr, const char *device)
++{
++ int i = 0;
++ int offset = 0;
++ weston_log("Opend device=%s\n", device);
+ if(fb_frame_buffer_open(go, device, &go->fb_info) < 0)
+ {
+ weston_log("Open frame buffer failed.\n");
+ return -1;
+ }
+-
+ go->renderSurf = zalloc(sizeof(struct g2d_surfaceEx) * go->nNumBuffers);
+ offset = go->fb_info.buffer_length/go->nNumBuffers;
+ for(i = 0; i < go->nNumBuffers; i++)
+@@ -1161,9 +1199,84 @@
+ go->offscreenSurface.base.planes[0] = go->offscreen_buf->buf_paddr;
+ g2d_clear(gr->handle, &go->offscreenSurface.base);
+ }
++ return 0;
++}
++
++static int
++g2d_renderer_output_create(struct weston_output *output, struct wl_display *wl_display, const char *device)
+
++ {
++ struct g2d_renderer *gr = get_renderer(output->compositor);
++ struct g2d_output_state *go;
++ int i;
++ int clone_display_num = 0;
++ int count = 0;
++ int k=0, dispCount = 0;
++ char displays[5][32];
++ weston_log("g2d_renderer_output_create device=%s\n", device);
++ count = strlen(device);
++
++ if(count > 0)
++ {
++ for(i= 0; i < count; i++)
++ {
++ if(device[i] == ',')
++ {
++ displays[dispCount][k] = '\0';
++ dispCount++;
++ k = 0;
++ continue;
++ }
++ else if(device[i] != ' ')
++ {
++ displays[dispCount][k++] = device[i];
++ }
++ }
++ displays[dispCount][k] = '\0';
++ clone_display_num = dispCount++;
++ weston_log("clone_display_num = %d\n", clone_display_num);
++ }
++ else
++ {
++ weston_log("Invalid device name\n");
++ return -1;
++ }
++
++ go = zalloc(sizeof *go);
++ if (go == NULL)
++ return -1;
++ go->clone_display_num = clone_display_num;
++ output->renderer_state = go;
++ gr->viv_global = gcoOS_WaylandCreateVivGlobal(wl_display);
++ getBufferNumber(go);
++
++ if(g2d_renderer_surface_create(go, gr, displays[0]) < 0)
++ {
++ weston_log("Create Render surface failed.\n");
++ return -1;
++ }
++
++ if(go->clone_display_num)
++ {
++ go->mirrorSurf = zalloc(sizeof(struct g2d_surfaceEx) * clone_display_num);
++ go->mirror_fb_info = zalloc(sizeof(struct fb_screeninfo) * clone_display_num);
++ if(go->mirrorSurf == NULL || go->mirror_fb_info == NULL)
++ return -1;
++
++ for(i = 0; i < clone_display_num; i++)
++ {
++ if(fb_frame_buffer_open(go, displays[i + 1], &go->mirror_fb_info[i]) < 0)
++ {
++ weston_log("Open frame buffer failed.\n");
++ return -1;
++ }
++ get_G2dSurface_from_screeninfo(&go->mirror_fb_info[i], &go->mirrorSurf[i]);
++ go->mirrorSurf[i].base.planes[0] = go->mirror_fb_info[i].physical;
++ g2d_clear(gr->handle, &go->mirrorSurf[i].base);
++ }
++ }
+ g2d_finish(gr->handle);
+- for (i = 0; i < 2; i++)
++ for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
+ pixman_region32_init(&go->buffer_damage[i]);
+ return 0;
+ }
+Index: weston-1.11.0/src/g2d-renderer.h
+===================================================================
+--- weston-1.11.0.orig/src/g2d-renderer.h 2016-10-06 13:17:41.738142236 -0500
++++ weston-1.11.0/src/g2d-renderer.h 2016-10-06 13:17:41.734142216 -0500
+@@ -27,13 +27,11 @@
+ #define __g2d_renderer_h_
+
+ #include "compositor.h"
++
+ #ifdef ENABLE_EGL
+ #include <EGL/egl.h>
+-#else
+-#include <HAL/gc_hal_eglplatform.h>
+ #endif
+
+-
+ struct g2d_renderer_interface {
+
+ int (*create)(struct weston_compositor *ec);
+Index: weston-1.11.0/src/main.c
+===================================================================
+--- weston-1.11.0.orig/src/main.c 2016-10-06 13:39:13.000000000 -0500
++++ weston-1.11.0/src/main.c 2016-10-06 13:39:39.000000000 -0500
+@@ -287,11 +287,12 @@
+ " --device=DEVICE\tThe framebuffer device to use\n"
+ #if defined ENABLE_EGL
+ " --no-use-gl\t\tDo not use the GL renderer\n"
+- " --use-g2d\t\tUse the G2D renderer\n\n");
++ " --use-g2d\t\tUse the G2D renderer\n"
+ #else
+ " --use-gl\t\tUse the GL renderer\n"
+- " --no-use-g2d\t\tDo not use the G2D renderer\n\n");
++ " --no-use-g2d\t\tDo not use the G2D renderer\n"
+ #endif
++ " --clone-mode\t\tClone display to multiple devices\n\n");
+ #endif
+
+ #if defined(BUILD_HEADLESS_COMPOSITOR)
+@@ -888,6 +889,7 @@
+ { WESTON_OPTION_BOOLEAN, "use-gl", 0, &config.use_gl },
+ { WESTON_OPTION_BOOLEAN, "no-use-g2d", 0, &no_use_g2d },
+ #endif
++ { WESTON_OPTION_BOOLEAN, "clone-mode", 0, &config.clone_mode },
+ };
+
+ parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);