/*
 * Copyright (c) 2016 Freescale Semiconductor, Inc.
 * Copyright © 2012 Intel Corporation
 * Copyright © 2015 Collabora, Ltd.
 * Copyright 2018 NXP
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include <math.h>
#include <assert.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <HAL/gc_hal.h>
#include <drm_fourcc.h>
#include <poll.h>
#include <errno.h>

#include <libweston/libweston.h>
#include "g2d-renderer.h"
#include "vertex-clipping.h"
#include "linux-dmabuf.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
#include "linux-explicit-synchronization.h"
#include "shared/fd-util.h"
#include "shared/helpers.h"
#include "shared/platform.h"

#define BUFFER_DAMAGE_COUNT 3
#define ALIGN_TO_16(a) (((a) + 15) & ~15)
#define ALIGN_TO_64(a) (((a) + 63) & ~63)

static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;

#ifndef PFNEGLUPDATEWAYLANDBUFFERWL
typedef EGLBoolean (EGLAPIENTRYP PFNEGLUPDATEWAYLANDBUFFERWL)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute);
#endif

struct wl_viv_buffer
{
	struct wl_resource *resource;
	gcoSURF  surface;
	gctINT32 width;
	gctINT32 height;
	gctINT32 format;
	gctUINT alignedWidth;
	gctUINT alignedHeight;
	gctUINT32 physical[3];
	gctUINT32 gpuBaseAddr;
	gceTILING tiling;
	gctINT32 fd;

	gctUINT32 ts_addr;
	gctUINT32 fc_enabled;
	gctUINT32 fcValue;
	gctUINT32 fcValueUpper;
	gctUINT32 compressed;
	gctUINT32 tileStatus_enabled;
};

typedef struct _g2dRECT
{
	int left;
	int top;
	int right;
	int bottom;
} g2dRECT;

struct fb_screeninfo {
	struct fb_var_screeninfo varinfo;
	struct fb_fix_screeninfo fixinfo;
	unsigned int x_resolution;
	unsigned int y_resolution;
	size_t buffer_length; /* length of frame buffer memory in bytes */
	size_t physical;
	size_t stride;
	size_t stride_bytes;
	enum g2d_format pixel_format; /* frame buffer pixel format */
	int fb_fd;
};

struct g2d_output_state {
	int current_buffer;
	pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
	struct g2d_surfaceEx *renderSurf;
	int nNumBuffers;
	int activebuffer;
	struct g2d_surfaceEx offscreenSurface;
	struct g2d_buf *offscreen_buf;
	struct fb_screeninfo fb_info;
	struct fb_screeninfo *mirror_fb_info;
	struct g2d_surfaceEx *mirrorSurf;
	struct g2d_surfaceEx *drm_hw_buffer;
	int directBlit;
	int clone_display_num;
	int width;
	int height;
};

struct g2d_surface_state {
	float color[4];
	struct weston_buffer_reference buffer_ref;
	struct weston_buffer_release_reference buffer_release_ref;
	int pitch; /* in pixels */
	int attached;
	pixman_region32_t texture_damage;
	struct g2d_surfaceEx g2d_surface;
	struct g2d_buf *shm_buf;
	struct g2d_buf *dma_buf;
	int shm_buf_length;
	int shm_buf_clrcolor;
	int set_shm_buf_clrcolor;
	int bpp;

	struct weston_surface *surface;
	struct wl_listener surface_destroy_listener;
	struct wl_listener renderer_destroy_listener;
};

struct g2d_renderer {
	struct weston_renderer base;
	struct wl_signal destroy_signal;
#ifdef ENABLE_EGL
	NativeDisplayType display;
	EGLDisplay egl_display;
	struct wl_display *wl_display;
	PFNEGLBINDWAYLANDDISPLAYWL bind_display;
	PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
	PFNEGLUPDATEWAYLANDBUFFERWL update_buffer;
#endif
	void *handle;
	int use_drm;
};

static int
g2d_renderer_create_surface(struct weston_surface *surface);

static inline struct g2d_surface_state *
get_surface_state(struct weston_surface *surface)
{
	if (!surface->renderer_state)
		g2d_renderer_create_surface(surface);
	return (struct g2d_surface_state *)surface->renderer_state;
}

static inline struct g2d_renderer *
get_renderer(struct weston_compositor *ec)
{
	return (struct g2d_renderer *)ec->renderer;
}

#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) > (b)) ? (b) : (a))
/*
 * Compute the boundary vertices of the intersection of the global coordinate
 * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
 * 'surf_rect' when transformed from surface coordinates into global coordinates.
 * The vertices are written to 'ex' and 'ey', and the return value is the
 * number of vertices. Vertices are produced in clockwise winding order.
 * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
 * polygon area.
 */
static int
calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
		pixman_box32_t *surf_rect, float *ex, float *ey)
{

	struct clip_context ctx;
	int i, n;
	float min_x, max_x, min_y, max_y;
	struct polygon8 surf = {
		{ surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
		{ surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
		4
	};

	ctx.clip.x1 = rect->x1;
	ctx.clip.y1 = rect->y1;
	ctx.clip.x2 = rect->x2;
	ctx.clip.y2 = rect->y2;

	/* transform surface to screen space: */
	for (i = 0; i < surf.n; i++)
		weston_view_to_global_float(ev, surf.x[i], surf.y[i],
						&surf.x[i], &surf.y[i]);

	/* find bounding box: */
	min_x = max_x = surf.x[0];
	min_y = max_y = surf.y[0];

	for (i = 1; i < surf.n; i++) {
		min_x = min(min_x, surf.x[i]);
		max_x = max(max_x, surf.x[i]);
		min_y = min(min_y, surf.y[i]);
		max_y = max(max_y, surf.y[i]);
	}

	/* First, simple bounding box check to discard early transformed
	 * surface rects that do not intersect with the clip region:
	 */
	if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
		(min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
		return 0;

	/* Simple case, bounding box edges are parallel to surface edges,
	 * there will be only four edges.  We just need to clip the surface
	 * vertices to the clip rect bounds:
	 */
	if (!ev->transform.enabled)
		return clip_simple(&ctx, &surf, ex, ey);

	/* Transformed case: use a general polygon clipping algorithm to
	 * clip the surface rectangle with each side of 'rect'.
	 * The algorithm is Sutherland-Hodgman, as explained in
	 * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
	 * but without looking at any of that code.
	 */
	n = clip_transformed(&ctx, &surf, ex, ey);

	if (n < 3)
		return 0;

	return n;
}

static void
calculate_rect_with_transform(int surfaceWidth, int surfaceHeight,
				  uint32_t transform, g2dRECT *rect)
{
	g2dRECT tmp = *rect;

	switch (transform) {
	case WL_OUTPUT_TRANSFORM_NORMAL:
	default:
		break;
	case WL_OUTPUT_TRANSFORM_270:
		rect->right = surfaceWidth - tmp.top;
		rect->left = rect->right - (tmp.bottom - tmp.top);
		rect->top = tmp.left;
		rect->bottom = rect->top + (tmp.right - tmp.left);
		break;
	case WL_OUTPUT_TRANSFORM_90:
		rect->left = tmp.top;
		rect->right = rect->left + (tmp.bottom - tmp.top);
		rect->bottom = surfaceHeight - tmp.left;
		rect->top = rect->bottom - (tmp.right - tmp.left);
		break;
	case WL_OUTPUT_TRANSFORM_180:
		rect->left = surfaceWidth - tmp.right;
		rect->right = rect->left + (tmp.right - tmp.left);
		rect->bottom = surfaceHeight - tmp.top;
		rect->top = rect->bottom - (tmp.bottom - tmp.top);
		break;
	}
}

static enum g2d_rotation
convert_transform_to_rot(uint32_t transform)
{
	enum g2d_rotation rot;
	switch(transform) {
	case WL_OUTPUT_TRANSFORM_NORMAL:
	default:
		rot = G2D_ROTATION_0;
		break;
	case WL_OUTPUT_TRANSFORM_90:
		/*For source rotation*/
		rot = G2D_ROTATION_90;
		break;
	case WL_OUTPUT_TRANSFORM_270:
		rot = G2D_ROTATION_270;
		break;
	case WL_OUTPUT_TRANSFORM_180:
		rot = G2D_ROTATION_180;
		break;
	}
	return rot;
}

static inline struct g2d_output_state *
get_output_state(struct weston_output *output)
{
	return (struct g2d_output_state *)output->renderer_state;
}

static void
g2d_getG2dTiling(IN gceTILING tiling, enum g2d_tiling* g2dTiling)
{
	switch(tiling)
	{
	case gcvLINEAR:
		*g2dTiling = G2D_LINEAR;
		break;
	case gcvTILED:
		*g2dTiling = G2D_TILED;
		break;
	case gcvSUPERTILED:
		*g2dTiling = G2D_SUPERTILED;
		break;
	default:
		weston_log("Error in function %s\n", __func__);
		break;
	}
}

static void
g2d_getG2dFormat(IN gceSURF_FORMAT Format, enum g2d_format* g2dFormat)
{
	switch(Format)
	{
	case gcvSURF_R5G6B5:
		*g2dFormat = G2D_RGB565;
		break;
	case gcvSURF_A8B8G8R8:
		*g2dFormat = G2D_RGBA8888;
		break;
	case gcvSURF_X8B8G8R8:
		*g2dFormat = G2D_RGBA8888;
		break;
	case gcvSURF_A8R8G8B8:
		*g2dFormat = G2D_BGRA8888;
		break;
	case gcvSURF_X8R8G8B8:
		*g2dFormat = G2D_BGRX8888;
		break;
	case gcvSURF_B5G6R5:
		*g2dFormat = G2D_BGR565;
		break;
	case gcvSURF_B8G8R8A8:
		*g2dFormat = G2D_ARGB8888;
		break;
	case gcvSURF_R8G8B8A8:
		*g2dFormat = G2D_ABGR8888;
		break;
	case gcvSURF_B8G8R8X8:
		*g2dFormat = G2D_XRGB8888;
		break;
	case gcvSURF_R8G8B8X8:
		*g2dFormat = G2D_XBGR8888;
		break;
	case gcvSURF_NV12:
		*g2dFormat = G2D_NV12;
		break;
	case gcvSURF_NV21:
		*g2dFormat = G2D_NV21;
		break;
	case gcvSURF_I420:
		*g2dFormat = G2D_I420;
		break;
	case gcvSURF_YV12:
		*g2dFormat = G2D_YV12;
		break;
	case gcvSURF_YUY2:
		*g2dFormat = G2D_YUYV;
		break;
	case gcvSURF_YVYU:
		*g2dFormat = G2D_YVYU;
		break;
	case gcvSURF_UYVY:
		*g2dFormat = G2D_UYVY;
		break;
	case gcvSURF_VYUY:
		*g2dFormat = G2D_VYUY;
		break;
	case gcvSURF_NV16:
		*g2dFormat = G2D_NV16;
		break;
	case gcvSURF_NV61:
		*g2dFormat = G2D_NV61;
		break;
	default:
		weston_log("Error in function %s, Format not supported\n", __func__);
		break;
	}
}

static int
g2d_getG2dFormat_from_pixman(IN pixman_format_code_t Format, enum g2d_format* g2dFormat)
{
	switch(Format)
	{
	case  PIXMAN_r5g6b5:
		*g2dFormat = G2D_RGB565;
		break;
	case PIXMAN_a8b8g8r8:
		*g2dFormat = G2D_RGBA8888;
		break;
	case PIXMAN_x8b8g8r8:
		*g2dFormat = G2D_RGBA8888;
		break;
	case PIXMAN_a8r8g8b8:
		*g2dFormat = G2D_BGRA8888;
		break;
	case PIXMAN_x8r8g8b8 :
		*g2dFormat = G2D_BGRX8888;
		break;
	case PIXMAN_b5g6r5:
		*g2dFormat = G2D_BGR565;
		break;
	case PIXMAN_b8g8r8a8:
		*g2dFormat = G2D_ARGB8888;
		break;
	case PIXMAN_r8g8b8a8:
		*g2dFormat = G2D_ABGR8888;
		break;
	case PIXMAN_b8g8r8x8:
		*g2dFormat = G2D_XRGB8888;
		break;
	case PIXMAN_r8g8b8x8:
		*g2dFormat = G2D_XBGR8888;
		break;
	case PIXMAN_yv12:
		*g2dFormat = G2D_YV12;
		break;
	case PIXMAN_yuy2:
		*g2dFormat = G2D_YUYV;
		break;
	default:
		weston_log("Error in function %s, Format(%d) not supported\n", __func__, Format);
		return -1;
	}
	return 0;
}

static void printG2dSurfaceInfo(struct g2d_surfaceEx* g2dSurface, const char* msg)
{
	weston_log("%s physicAddr = %x left = %d right = %d top=%d bottom=%d stride= %d tiling = %d, format=%d \n",
				msg,
				g2dSurface->base.planes[0],
				g2dSurface->base.left,
				g2dSurface->base.right,
				g2dSurface->base.top,
				g2dSurface->base.bottom,
				g2dSurface->base.stride,
				g2dSurface->tiling,
				g2dSurface->base.format);
}

static int
get_g2dSurface(struct wl_viv_buffer *buffer, struct g2d_surfaceEx *g2dSurface)
{
	if(buffer->width <= 0 || buffer->height <= 0)
	{
		weston_log("invalid EGL buffer in function %s\n", __func__);
		return -EINVAL;
	}
	g2d_getG2dFormat(buffer->format, &g2dSurface->base.format);
	g2d_getG2dTiling(buffer->tiling, &g2dSurface->tiling);
	g2dSurface->base.planes[0] = buffer->physical[0] + buffer->gpuBaseAddr;
	g2dSurface->base.planes[1] = buffer->physical[1] + buffer->gpuBaseAddr;
	g2dSurface->base.planes[2] = buffer->physical[2] + buffer->gpuBaseAddr;
	g2dSurface->base.left = 0;
	g2dSurface->base.top = 0;
	g2dSurface->base.right = buffer->width;
	g2dSurface->base.bottom = buffer->height;
	g2dSurface->base.stride = buffer->alignedWidth;
	g2dSurface->base.width	= buffer->width;
	g2dSurface->base.height = buffer->height;
	g2dSurface->base.rot	= G2D_ROTATION_0;

	if(buffer->ts_addr && buffer->tileStatus_enabled)
	{
		g2dSurface->tiling             |= G2D_TILED_STATUS;
		g2dSurface->ts.ts_addr         = buffer->ts_addr;
		g2dSurface->ts.fc_enabled      = buffer->fc_enabled;
		g2dSurface->ts.fc_value        = buffer->fcValue;
		g2dSurface->ts.fc_value_upper  = buffer->fcValueUpper;
	}

	return 0;
}

static void
g2d_SetSurfaceRect(struct g2d_surfaceEx* g2dSurface, g2dRECT* rect)
{
	if(g2dSurface && rect)
	{
		g2dSurface->base.left	= rect->left;
		g2dSurface->base.top	= rect->top;
		g2dSurface->base.right	= rect->right;
		g2dSurface->base.bottom = rect->bottom;
	}
}

#define _hasAlpha(format) (format==G2D_RGBA8888 || format==G2D_BGRA8888 \
	|| format==G2D_ARGB8888 || format==G2D_ABGR8888)

static int
g2d_blit_surface(void *handle, struct g2d_surfaceEx * srcG2dSurface, struct g2d_surfaceEx *dstG2dSurface,
	g2dRECT *srcRect, g2dRECT *dstRect)
{
	g2d_SetSurfaceRect(srcG2dSurface, srcRect);
	g2d_SetSurfaceRect(dstG2dSurface, dstRect);
	srcG2dSurface->base.blendfunc = G2D_ONE;
	dstG2dSurface->base.blendfunc = G2D_ONE_MINUS_SRC_ALPHA;
	if(!(_hasAlpha(srcG2dSurface->base.format))){
		g2d_disable(handle, G2D_BLEND);
	}

	if(g2d_blitEx(handle, srcG2dSurface, dstG2dSurface)){
		printG2dSurfaceInfo(srcG2dSurface, "SRC:");
		printG2dSurfaceInfo(dstG2dSurface, "DST:");
		return -1;
	}
	return 0;
}

static void
g2d_flip_surface(struct weston_output *output)
{
	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_info.fb_fd, FBIOPAN_DISPLAY, &(go->fb_info.varinfo)) < 0)
	{
		weston_log("FBIOPAN_DISPLAY Failed\n");
	}
	go->activebuffer = (go->activebuffer + 1)  % go->nNumBuffers;
}

static void
copy_to_framebuffer(struct weston_output *output, pixman_region32_t* output_damage)
{
	struct g2d_renderer *gr = get_renderer(output->compositor);
	struct g2d_output_state *go = get_output_state(output);
	g2dRECT clipRect = {0};

	if((!go->directBlit && go->nNumBuffers == 1) || (go->clone_display_num))
	{
		clipRect.left	= output_damage->extents.x1;
		clipRect.top	= output_damage->extents.y1;
		clipRect.right	= output_damage->extents.x2;
		clipRect.bottom = output_damage->extents.y2;

		if(clipRect.left >= go->offscreenSurface.base.width)
		{
			clipRect.left -= go->offscreenSurface.base.width;
			clipRect.right -= go->offscreenSurface.base.width;
		}
	}

	if(!go->directBlit && go->nNumBuffers == 1)
	{
		g2dRECT srcRect  = {0, 0, go->offscreenSurface.base.width, go->offscreenSurface.base.height};
		g2dRECT dstrect  = srcRect;
		clipRect = srcRect;
		g2d_set_clipping(gr->handle, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
		g2d_blit_surface(gr->handle, &go->offscreenSurface,
			&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};
			if(go->directBlit || go->nNumBuffers > 1)
			{
				g2d_blit_surface(gr->handle, &go->renderSurf[go->activebuffer],
				&go->mirrorSurf[i], &srcRect, &dstrect);
			}
			else
			{
				g2d_blit_surface(gr->handle, &go->offscreenSurface,
					&go->mirrorSurf[i], &srcRect, &dstrect);
			}
		}
	}

	g2d_finish(gr->handle);

	if(go->nNumBuffers > 1)
	{
		g2d_flip_surface(output);
	}
}

static int
is_view_visible(struct weston_view *view)
{
	/* Return false, if surface is guaranteed to be totally obscured. */
	int ret;
	pixman_region32_t unocc;

	pixman_region32_init(&unocc);
	pixman_region32_subtract(&unocc, &view->transform.boundingbox,
				 &view->clip);
	ret = pixman_region32_not_empty(&unocc);
	pixman_region32_fini(&unocc);

	return ret;
}
 
static void
use_output(struct weston_output *output)
{
	struct weston_compositor *compositor = output->compositor;
	struct weston_view *view;
	struct g2d_output_state *go = get_output_state(output);
	int visibleViews=0;
	int fullscreenViews=0;

	if(go->nNumBuffers == 1)
	{
		wl_list_for_each_reverse(view, &compositor->view_list, link)
			if (view->plane == &compositor->primary_plane && is_view_visible(view))
			{
				visibleViews++;
				if(view->surface->width == go->width && view->surface->height == go->height)
				{
					pixman_box32_t *bb_rects;
					int nbb=0;
					bb_rects = pixman_region32_rectangles(&view->transform.boundingbox, &nbb);
					if(nbb == 1)
						if(bb_rects[0].x1 == 0 && bb_rects[0].y1 ==0)
							fullscreenViews++;
				}
			}

		go->directBlit = ((visibleViews == 1) || (fullscreenViews > 1));
	}
}

static void
g2d_clip_rects(enum wl_output_transform transform,
			g2dRECT *srcRect,
			g2dRECT *dstrect,
			int dstWidth,
			int dstHeight)
{
	int srcWidth = srcRect->right - srcRect->left;
	int srcHeight = srcRect->bottom - srcRect->top;
	float scale_v = 1.0f;
	float scale_h = 1.0f;

	if(transform == WL_OUTPUT_TRANSFORM_90
		|| transform == WL_OUTPUT_TRANSFORM_270)
	{
		scale_h = (float)srcHeight / (dstrect->right - dstrect->left);
		scale_v = (float)srcWidth / (dstrect->bottom - dstrect->top);
	}
	else
	{
		scale_h = (float)srcWidth / (dstrect->right - dstrect->left);
		scale_v = (float)srcHeight / (dstrect->bottom - dstrect->top);
	}
	switch (transform) {
	case WL_OUTPUT_TRANSFORM_NORMAL:
		if(dstrect->left < 0)
		{
			srcRect->left += floorf((float)(-dstrect->left) * scale_h);
			dstrect->left = 0;
			if(srcRect->left >= srcRect->right)
				return;
		}
		if(dstrect->right > dstWidth)
		{
			srcRect->right -= floorf((float)(dstrect->right - dstWidth) * scale_h);
			dstrect->right = dstWidth;
			if(srcRect->right <= srcRect->left)
				return;
		}
		if(dstrect->top < 0)
		{
			srcRect->top += floorf((float)(-dstrect->top) * scale_v);
			dstrect->top = 0;
			if(srcRect->top >= srcRect->bottom)
				return;
		}
		if(dstrect->bottom > dstHeight)
		{
			srcRect->bottom -= floorf((float)(dstrect->bottom - dstHeight) * scale_v);
			dstrect->bottom = dstHeight;
			if(srcRect->bottom < 0)
				return;
		}
		break;
	case WL_OUTPUT_TRANSFORM_270:
		if(dstrect->left < 0)
		{
			srcRect->bottom -= floorf((float)(-dstrect->left) * scale_h);
			dstrect->left = 0;
			if(srcRect->top >= srcRect->bottom)
					return;
		}
		if(dstrect->bottom > dstHeight)
		{
			srcRect->right -= floorf((float)(dstrect->bottom - dstHeight) * scale_v);
			dstrect->bottom = dstHeight;
			if(srcRect->right < 0)
				return;
		}
		if(dstrect->top < 0)
		{
			srcRect->left += floorf((float)(-dstrect->top) * scale_h);
			dstrect->top = 0;
			if(srcRect->left > srcRect->right)
				return;
		}
		break;
	case WL_OUTPUT_TRANSFORM_90:
		if(dstrect->left < 0)
		{
			srcRect->top += floorf((float)(-dstrect->left) * scale_h);
			dstrect->left = 0;
			if(srcRect->top >= srcRect->bottom)
					return;
		}
		if(dstrect->top < 0)
		{
			srcRect->right -= floorf((float)(-dstrect->top) * scale_v);
			dstrect->top = 0;
			if(srcRect->left >= srcRect->right)
				return;
		}
		if(dstrect->bottom > dstHeight)
		{
			srcRect->left += floorf((float)(dstrect->bottom - dstHeight) * scale_v);
			dstrect->bottom = dstHeight;
			if(srcRect->right <= srcRect->left)
				return;
		}
		if(dstrect->right > dstWidth)
		{
			srcRect->bottom -= floorf((float)(dstrect->right - dstWidth) * scale_h);
			dstrect->right = dstWidth;
			if(srcRect->bottom <= srcRect->top)
				return;
		}
		break;
	case WL_OUTPUT_TRANSFORM_180:
		if(dstrect->left < 0)
		{
			srcRect->right -= floorf((float)(-dstrect->left) * scale_h);
			dstrect->left = 0;
			if(srcRect->left >= srcRect->right)
					return;
		}
		if(dstrect->right > dstWidth)
		{
			srcRect->left += floorf((float)(dstrect->right - dstWidth) * scale_h);
			dstrect->right = dstWidth;
			if(srcRect->right <= srcRect->left)
				return;
		}
		if(dstrect->top < 0)
		{
			srcRect->bottom -= floorf((float)(-dstrect->top) * scale_v);
			dstrect->top = 0;
			if(srcRect->top >= srcRect->bottom)
				return;
		}
		break;
	default:
		break;
	}
}

static int
g2d_renderer_read_pixels(struct weston_output *output,
				   pixman_format_code_t format, void *pixels,
				   uint32_t x, uint32_t y,
				   uint32_t width, uint32_t height)
{
	struct g2d_surfaceEx  dstSurface;
	struct g2d_surfaceEx  *srcSurface;
	struct g2d_output_state *go = get_output_state(output);
	struct g2d_renderer *gr = get_renderer(output->compositor);
	struct g2d_buf *read_buf = NULL;
	enum g2d_format dst_format;
	g2dRECT	srcRect  = {x, y, x + width, y + height};
	g2dRECT dstRect  = {0, 0, width, height};

	if( g2d_getG2dFormat_from_pixman(format, &dst_format))
		return -1;

	read_buf = g2d_alloc(width * height * 4, 0);
	if( !read_buf)
		return -1;

	if(go->drm_hw_buffer && gr->use_drm)
	{
		srcSurface = go->drm_hw_buffer;
	}
	else
	{
		if(go->nNumBuffers > 1 || go->directBlit)
		{
			srcSurface = &go->renderSurf[go->activebuffer];
		}
		else
		{
			srcSurface = &go->offscreenSurface;
		}
	}

	dstSurface.base.planes[0] = read_buf->buf_paddr;
	dstSurface.base.format = dst_format;
	dstSurface.base.width  = width;
	dstSurface.base.height = height;
	dstSurface.base.stride = width;
	dstSurface.base.rot    = G2D_FLIP_V;
	if(g2d_blit_surface(gr->handle, srcSurface, &dstSurface, &srcRect, &dstRect)) {
		g2d_free(read_buf);
		return -1;
	}
	g2d_finish(gr->handle);

	memcpy(pixels, read_buf->buf_vaddr, width * height * PIXMAN_FORMAT_BPP(format)/8);
	g2d_free(read_buf);

	return 0;
}

static int g2d_int_from_double(double d)
{
	return wl_fixed_to_int(wl_fixed_from_double(d));
}

static void
repaint_region(struct weston_view *ev, struct weston_output *output, struct g2d_output_state *go, pixman_region32_t *region,
		pixman_region32_t *surf_region){

	struct g2d_renderer *gr = get_renderer(ev->surface->compositor);
	struct g2d_surface_state *gs = get_surface_state(ev->surface);

	pixman_box32_t *rects, *surf_rects, *bb_rects;
	int i, j, nrects, nsurf, nbb=0;
	g2dRECT srcRect = {0};
	g2dRECT dstrect = {0};
	g2dRECT clipRect = {0};
	int dstWidth = 0;
	int dstHeight = 0;
	struct g2d_surfaceEx *dstsurface;
	struct g2d_surfaceEx srcsurface = gs->g2d_surface;
	uint32_t view_transform = ev->surface->buffer_viewport.buffer.transform;
	int src_x = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_x);
	int src_y = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_y);
	int src_width = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_width);
	int src_height = wl_fixed_to_int (ev->surface->buffer_viewport.buffer.src_height);
	int scale = ev->surface->buffer_viewport.buffer.scale;
	if (ev->alpha < 1.0) {
		/* Skip the render for global alpha, a workaround to disable the
		   fade effect, it created garbage info in the sequence test.*/
		return;
	}

	bb_rects = pixman_region32_rectangles(&ev->transform.boundingbox, &nbb);

	if(!gs->attached || nbb <= 0)
	{
		return;
	}

	rects = pixman_region32_rectangles(region, &nrects);
	surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
	if(src_width != -1 && src_width > 0 && src_x >=0 && src_y >= 0
		&& src_x < gs->g2d_surface.base.width
		&& src_y < gs->g2d_surface.base.height)
	{
		srcRect.left = src_x * scale;
		srcRect.top = src_y * scale;
		srcRect.right = min (gs->g2d_surface.base.width, (src_x + src_width) * scale);
		srcRect.bottom = min (gs->g2d_surface.base.height, (src_y + src_height) * scale);
	}
	else
	{
		srcRect.left = srcsurface.base.left;
		srcRect.top  = srcsurface.base.top;
		srcRect.right  = srcsurface.base.right;
		srcRect.bottom = srcsurface.base.bottom;
	}
	if(go->drm_hw_buffer && gr->use_drm)
	{
		dstsurface = go->drm_hw_buffer;
	}
	else
	{
		if(go->nNumBuffers > 1 || go->directBlit)
		{
			dstsurface = &go->renderSurf[go->activebuffer];
		}
		else
		{
			dstsurface = &go->offscreenSurface;
		}
	}
	dstWidth  = dstsurface->base.width;
	dstHeight = dstsurface->base.height;
	/*Calculate the destrect once for all*/
	dstrect.left = bb_rects[0].x1;
	dstrect.top = bb_rects[0].y1;
	dstrect.right = bb_rects[0].x2;
	dstrect.bottom = bb_rects[0].y2;
	/*Multi display support*/
	if(output->x > 0)
	{
		dstrect.left = dstrect.left - output->x;
		dstrect.right = dstrect.right - output->x;
	}

	calculate_rect_with_transform(dstsurface->base.width,
					  dstsurface->base.height,
					  output->transform, &dstrect);

	if(view_transform != output->transform)
	{
		g2d_clip_rects(output->transform, &srcRect, &dstrect, dstWidth, dstHeight);
		srcsurface.base.rot = convert_transform_to_rot(output->transform);
	} else {
		/* if the view is transformed by compositor, we only need handle input crop
		 * according to dst rect */
		g2d_clip_rects(WL_OUTPUT_TRANSFORM_NORMAL, &srcRect, &dstrect, dstWidth, dstHeight);
	}

	for (i = 0; i < nrects; i++)
	{
		pixman_box32_t *rect = &rects[i];
		gctFLOAT min_x, max_x, min_y, max_y;

		for (j = 0; j < nsurf; j++)
		{
			pixman_box32_t *surf_rect = &surf_rects[j];
			gctFLOAT ex[8], ey[8];			/* edge points in screen space */
			int n;
			int m=0;
			n = calculate_edges(ev, rect, surf_rect, ex, ey);
			if (n < 3)
				continue;

			min_x = max_x = ex[0];
			min_y = max_y = ey[0];
			for (m = 1; m < n; m++)
			{
				min_x = min(min_x, ex[m]);
				max_x = max(max_x, ex[m]);
				min_y = min(min_y, ey[m]);
				max_y = max(max_y, ey[m]);
			}

			clipRect.left = g2d_int_from_double(min_x);
			clipRect.top = g2d_int_from_double(min_y);
			clipRect.right = g2d_int_from_double(max_x);
			clipRect.bottom = g2d_int_from_double(max_y);

			if(output->x > 0)
			{
				clipRect.left = clipRect.left - output->x;
				clipRect.right = clipRect.right - output->x;
			}
			/* Need compute the clip rect with transform */
			calculate_rect_with_transform(dstsurface->base.width,
							  dstsurface->base.height,
							  output->transform, &clipRect);
			if(clipRect.left >= clipRect.right || clipRect.top >= clipRect.bottom)
			{
				return;
			}
			g2d_set_clipping(gr->handle, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);

			if(gs->g2d_surface.base.width == 1
				&& gs->g2d_surface.base.height == 1
				&& gs->set_shm_buf_clrcolor ==1)
			{
				struct g2d_surface tmp_surface = dstsurface->base;
				memcpy(&tmp_surface.left, &clipRect.left, sizeof(clipRect));
				tmp_surface.clrcolor = gs->shm_buf_clrcolor;
				g2d_clear(gr->handle, &tmp_surface);
			}
			else
			{
				g2d_blit_surface(gr->handle, &srcsurface, dstsurface, &srcRect, &dstrect);
			}
		}
	}
}

static int sync_wait(int fd, int timeout)
{
    struct pollfd fds;
    int ret;

    if (fd < 0) {
        errno = EINVAL;
        return -1;
    }

    fds.fd = fd;
    fds.events = POLLIN;

    do {
        ret = poll(&fds, 1, timeout);
        if (ret > 0) {
            if (fds.revents & (POLLERR | POLLNVAL)) {
                errno = EINVAL;
                return -1;
            }
            return 0;
        } else if (ret == 0) {
            errno = ETIME;
            return -1;
        }
    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));

    return ret;
}

static int
ensure_surface_buffer_is_ready(struct g2d_renderer *gr,
			       struct g2d_surface_state *gs)
{
	int ret = 0;
	struct weston_surface *surface = gs->surface;
	struct weston_buffer *buffer = gs->buffer_ref.buffer;

	if (!buffer)
		return 0;

	if(!wl_shm_buffer_get(buffer->resource) && !linux_dmabuf_buffer_get(buffer->resource)){
		/*Update vivBuffer and set g2d surface */
		struct wl_viv_buffer *vivBuffer = wl_resource_get_user_data(buffer->resource);

		if (gr->update_buffer)
			gr->update_buffer(gr->egl_display, (void *)buffer->resource, EGL_WAYLAND_BUFFER_WL);

		ret = get_g2dSurface(vivBuffer, &gs->g2d_surface);

		if (ret < 0)
			return ret;
	}

	if (surface->acquire_fence_fd < 0)
		return 0;

	ret = sync_wait(surface->acquire_fence_fd, 2000);

	if (ret < 0 && errno == ETIME){
		/* Print a warning. */
		weston_log("%s: Warning: wait for fence fd=%d", __func__, surface->acquire_fence_fd);

		/* Wait for ever. */
		ret = sync_wait(surface->acquire_fence_fd, -1);
	}

	return ret;
}

static void
draw_view(struct weston_view *ev, struct weston_output *output,
		 pixman_region32_t *damage) /* in global coordinates */
{
	struct weston_compositor *ec = ev->surface->compositor;	
	struct g2d_output_state *go = get_output_state(output);
	struct g2d_surface_state *gs = get_surface_state(ev->surface);
	struct g2d_renderer *gr = get_renderer(ec);
	/* repaint bounding region in global coordinates: */
	pixman_region32_t repaint;
	/* opaque region in surface coordinates: */
	pixman_region32_t surface_opaque;
	/* non-opaque region in surface coordinates: */
	pixman_region32_t surface_blend;

	pixman_region32_init(&repaint);
	pixman_region32_intersect(&repaint,
				  &ev->transform.boundingbox, damage);
	pixman_region32_subtract(&repaint, &repaint, &ev->clip);

	if (!pixman_region32_not_empty(&repaint))
		goto out;

	if (ensure_surface_buffer_is_ready(gr, gs) < 0)
		goto out;

	/* blended region is whole surface minus opaque region: */
	pixman_region32_init_rect(&surface_blend, 0, 0,
				  ev->surface->width, ev->surface->height);
	if (ev->geometry.scissor_enabled)
		pixman_region32_intersect(&surface_blend, &surface_blend,
					  &ev->geometry.scissor);
	pixman_region32_subtract(&surface_blend, &surface_blend,
				 &ev->surface->opaque);

	/* XXX: Should we be using ev->transform.opaque here? */
	pixman_region32_init(&surface_opaque);
	if (ev->geometry.scissor_enabled)
		pixman_region32_intersect(&surface_opaque,
					  &ev->surface->opaque,
					  &ev->geometry.scissor);
	else
		pixman_region32_copy(&surface_opaque, &ev->surface->opaque);

	if (pixman_region32_not_empty(&surface_opaque)) {
		if (ev->alpha < 1.0) {
			g2d_enable(gr->handle, G2D_BLEND);
			g2d_enable(gr->handle, G2D_GLOBAL_ALPHA);
			gs->g2d_surface.base.global_alpha = ev->alpha * 0xFF;
		}
		repaint_region(ev, output, go, &repaint, &surface_opaque);
		g2d_disable(gr->handle, G2D_GLOBAL_ALPHA);
		g2d_disable(gr->handle, G2D_BLEND);
	}

	if (pixman_region32_not_empty(&surface_blend)) {
		g2d_enable(gr->handle, G2D_BLEND);
		if (ev->alpha < 1.0) {
			g2d_enable(gr->handle, G2D_GLOBAL_ALPHA);
			gs->g2d_surface.base.global_alpha = ev->alpha * 0xFF;
		}
		repaint_region(ev, output, go, &repaint, &surface_blend);
		g2d_disable(gr->handle, G2D_GLOBAL_ALPHA);
		g2d_disable(gr->handle, G2D_BLEND);
	}
	pixman_region32_fini(&surface_blend);
	pixman_region32_fini(&surface_opaque);

out:
	pixman_region32_fini(&repaint);
}

static void
repaint_views(struct weston_output *output, pixman_region32_t *damage)
{
	struct weston_compositor *compositor = output->compositor;
	struct weston_view *view;

	wl_list_for_each_reverse(view, &compositor->view_list, link)
		if (view->plane == &compositor->primary_plane)
			draw_view(view, output, damage);
}

static void
output_get_damage(struct weston_output *output,
		  pixman_region32_t *buffer_damage)
{
	struct g2d_output_state *go = get_output_state(output);
	int i;

	for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
		pixman_region32_union(buffer_damage,
			buffer_damage,
			&go->buffer_damage[i]);
}

static void
output_rotate_damage(struct weston_output *output,
			 pixman_region32_t *output_damage)
{
	struct g2d_output_state *go = get_output_state(output);

	go->current_buffer = (go->current_buffer + 1) % BUFFER_DAMAGE_COUNT;

	pixman_region32_copy(&go->buffer_damage[go->current_buffer], output_damage);
}

#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
static void
g2d_update_buffer_release_fences(struct weston_compositor *compositor,
			     int fence_fd)
{
	struct weston_view *view;

	wl_list_for_each_reverse(view, &compositor->view_list, link) {
		struct g2d_surface_state *gs;
		struct weston_buffer_release *buffer_release;

		if (view->plane != &compositor->primary_plane)
			continue;

		gs = get_surface_state(view->surface);
		buffer_release = gs->buffer_release_ref.buffer_release;

		if(!buffer_release) {
			continue;
		}

		/* If we have a buffer_release then it means we support fences,
		 * and we should be able to create the release fence. If we
		 * can't, something has gone horribly wrong, so disconnect the
		 * client.
		 */
		if (fence_fd == -1) {
			fd_clear(&buffer_release->fence_fd);
			continue;
		}

		fd_update(&buffer_release->fence_fd, dup(fence_fd));
	}
}
#endif

static void
g2d_renderer_repaint_output(struct weston_output *output,
				 pixman_region32_t *output_damage)
{
	struct weston_compositor *compositor = output->compositor;
	struct g2d_renderer *gr = get_renderer(compositor);
	pixman_region32_t buffer_damage, total_damage;
#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
	struct g2d_output_state *go = get_output_state(output);
#endif
	int fence_fd = -1;

	use_output(output);

	pixman_region32_init(&total_damage);
	pixman_region32_init(&buffer_damage);

	output_get_damage(output, &buffer_damage);
	output_rotate_damage(output, output_damage);
	pixman_region32_union(&total_damage, &buffer_damage, output_damage);

	repaint_views(output, &total_damage);

	pixman_region32_fini(&total_damage);
	pixman_region32_fini(&buffer_damage);

#if G2D_VERSION_MAJOR >= 2 && defined(BUILD_DRM_COMPOSITOR)
	fence_fd = g2d_create_fence_fd(gr->handle);
	g2d_update_buffer_release_fences(compositor, fence_fd);

	fd_clear(&go->drm_hw_buffer->reserved[0]);
	go->drm_hw_buffer->reserved[0] = fence_fd;
#endif

	if(fence_fd == -1)
		g2d_finish(gr->handle);

	wl_signal_emit(&output->frame_signal, output_damage);
	if(!gr->use_drm)
		copy_to_framebuffer(output, output_damage);
}

static void
g2d_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer)
{
	struct wl_viv_buffer *vivBuffer = wl_resource_get_user_data(buffer->resource);
	buffer->width = vivBuffer->width;
	buffer->height = vivBuffer->height;
}

static void
g2d_renderer_copy_shm_buffer(struct g2d_surface_state *gs, struct weston_buffer *buffer)
{
	int alignedWidth = ALIGN_TO_16(buffer->width);
	int height = 0;
	uint8_t *src = wl_shm_buffer_get_data(buffer->shm_buffer);
	uint8_t *dst = gs->shm_buf->buf_vaddr;
	int bpp = gs->bpp;
	int plane_size[3] = {0,};
	int src_plane_offset[3] = {0,};
	int dst_plane_offset[3] = {0,};
	int uv_src_stride = 0;
	int uv_dst_stride = 0;
	int n_planes = 0;
	int i, j;

	switch (wl_shm_buffer_get_format(buffer->shm_buffer)) {
		case WL_SHM_FORMAT_XRGB8888:
		case WL_SHM_FORMAT_ARGB8888:
		case WL_SHM_FORMAT_RGB565:
			n_planes = 1;
			height = buffer->height;
			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
			break;
		case WL_SHM_FORMAT_YUYV:
			n_planes = 1;
			height = ALIGN_TO_16(buffer->height);
			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
			break;
		case WL_SHM_FORMAT_NV12:
			n_planes = 2;
			height = ALIGN_TO_16(buffer->height);
			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
			plane_size[1] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height / 2;
			src_plane_offset[1] = plane_size[0];
			dst_plane_offset[1] = alignedWidth * height;
			uv_src_stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
			uv_dst_stride = alignedWidth;
			break;
		case WL_SHM_FORMAT_YUV420:
			n_planes = 3;
			height = ALIGN_TO_16(buffer->height);
			plane_size[0] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height;
			plane_size[1] = wl_shm_buffer_get_stride(buffer->shm_buffer)*buffer->height / 4;
			plane_size[2] = plane_size[1];
			src_plane_offset[1] = plane_size[0];
			src_plane_offset[2] = plane_size[0] + plane_size[1];
			dst_plane_offset[1] = alignedWidth * height;
			dst_plane_offset[2] = dst_plane_offset[1] + alignedWidth * height / 4;
			uv_src_stride = wl_shm_buffer_get_stride(buffer->shm_buffer) / 2;
			uv_dst_stride = alignedWidth / 2;
			break;
		default:
			weston_log("warning: copy shm buffer meet unknown format: %08x\n",
				   wl_shm_buffer_get_format(buffer->shm_buffer));
			return;
	}

	wl_shm_buffer_begin_access(buffer->shm_buffer);
	if(alignedWidth == buffer->width && height == buffer->height)
	{
		for (i = 0; i < n_planes; i++)
			memcpy (dst + dst_plane_offset[i], src + src_plane_offset[i], plane_size[i]);
	}
	else
	{
		int src_stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
		int dst_stride = alignedWidth * bpp;
		/* copy the 1st plane */
		for (i = 0; i < buffer->height; i++)
		{
			memcpy(dst + dst_plane_offset[0] + dst_stride * i, src + src_plane_offset[0] + src_stride * i, src_stride);
		}
		/* copy the rest plane */
		for (i = 1; i < n_planes; i++)
		{
			for (j = 0; j < buffer->height / 2; j++)
			{
				memcpy(dst + dst_plane_offset[i] + uv_dst_stride * j, src + src_plane_offset[i] + uv_src_stride * j, uv_src_stride);
			}
		}
		/* Some garbage was found in 6dl board, This workaround will use
		 * g2d_clear instead of g2d_blit for this special source
		 */
		if(buffer->width == 1
			&& buffer->height == 1
			&& wl_shm_buffer_get_format(buffer->shm_buffer) == WL_SHM_FORMAT_ARGB8888)
		{
			uint8_t *clrcolor = gs->shm_buf->buf_vaddr;
			gs->shm_buf_clrcolor = (clrcolor[0] << 16) | (clrcolor[1] << 8) | (clrcolor[2]) | (clrcolor[3] << 24);
			gs->set_shm_buf_clrcolor = 1;
		}
	}
	wl_shm_buffer_end_access(buffer->shm_buffer);
}

static void
g2d_renderer_flush_damage(struct weston_surface *surface)
{
	struct g2d_surface_state *gs = get_surface_state(surface);
	struct weston_buffer *buffer = gs->buffer_ref.buffer;
	struct weston_view *view;
	int texture_used;
	pixman_region32_union(&gs->texture_damage,
				  &gs->texture_damage, &surface->damage);

	if (!buffer)
		return;

	texture_used = 0;
	wl_list_for_each(view, &surface->views, surface_link) {
		if (view->plane == &surface->compositor->primary_plane) {
			texture_used = 1;
			break;
		}
	}
	if (!texture_used)
		return;

	if (!pixman_region32_not_empty(&gs->texture_damage))
		goto done;

	if(wl_shm_buffer_get(buffer->resource))
	{
		g2d_renderer_copy_shm_buffer(gs, buffer);
	}
	else
	{
		g2d_renderer_attach_egl(surface, buffer);
	}

done:
	pixman_region32_fini(&gs->texture_damage);
	pixman_region32_init(&gs->texture_damage);

	weston_buffer_reference(&gs->buffer_ref, NULL);
	weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
}

static void
g2d_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
			struct wl_shm_buffer *shm_buffer)
{
	struct g2d_surface_state *gs = get_surface_state(es);
	int buffer_length = 0;
	int alloc_new_buff = 1;
	int alignedWidth = 0;
	int height = 0;
	enum g2d_format g2dFormat = 0;
	buffer->shm_buffer = shm_buffer;
	buffer->width = wl_shm_buffer_get_width(shm_buffer);
	buffer->height = wl_shm_buffer_get_height(shm_buffer);
	alignedWidth = ALIGN_TO_16(buffer->width);

	switch (wl_shm_buffer_get_format(shm_buffer)) {
	case WL_SHM_FORMAT_XRGB8888:
		g2dFormat = G2D_BGRX8888;
		gs->bpp = 4;
		break;
	case WL_SHM_FORMAT_ARGB8888:
		g2dFormat = G2D_BGRA8888;
		gs->bpp = 4;
		break;
	case WL_SHM_FORMAT_RGB565:
		g2dFormat = G2D_RGB565;
		gs->bpp = 2;
		break;
	case WL_SHM_FORMAT_YUYV:
		g2dFormat = G2D_YUYV;
		height = ALIGN_TO_16(buffer->height);
		buffer_length = alignedWidth * height * 2;
		gs->bpp = 2;
		break;
	case WL_SHM_FORMAT_YUV420:
		g2dFormat = G2D_I420;
		height = ALIGN_TO_16(buffer->height);
		buffer_length = alignedWidth * height * 3/2;
		gs->bpp = 1;
		break;
	case WL_SHM_FORMAT_NV12:
		g2dFormat = G2D_NV12;
		height = ALIGN_TO_16(buffer->height);
		buffer_length = alignedWidth * height * 3/2;
		gs->bpp = 1;
		break;
	default:
		weston_log("warning: unknown shm buffer format: %08x\n",
			   wl_shm_buffer_get_format(shm_buffer));
		return;
	}

	if (height == 0)
		height = buffer->height;

	if (buffer_length == 0)
		buffer_length = alignedWidth * buffer->height * gs->bpp;

	/* Only allocate a new g2d buff if it is larger than existing one.*/
	gs->shm_buf_length = buffer_length;
	if(gs->shm_buf && gs->shm_buf->buf_size > buffer_length)
	{
		alloc_new_buff = 0;
	}

	if(alloc_new_buff)
	{
		if(gs->shm_buf)
			g2d_free(gs->shm_buf);
		gs->shm_buf = g2d_alloc(buffer_length, 0);
		gs->g2d_surface.base.planes[0] = gs->shm_buf->buf_paddr;
		gs->g2d_surface.base.planes[1] = gs->g2d_surface.base.planes[0] + alignedWidth * height;
		gs->g2d_surface.base.planes[2] = gs->g2d_surface.base.planes[1] + alignedWidth * height / 4;
	}

	gs->g2d_surface.base.left = 0;
	gs->g2d_surface.base.top  = 0;
	gs->g2d_surface.base.right	= buffer->width;
	gs->g2d_surface.base.bottom = buffer->height;
	gs->g2d_surface.base.stride = alignedWidth;
	gs->g2d_surface.base.width	= buffer->width;
	gs->g2d_surface.base.height = height;
	gs->g2d_surface.base.rot	= G2D_ROTATION_0;
	gs->g2d_surface.base.clrcolor = 0xFF400000;
	gs->g2d_surface.tiling = G2D_LINEAR;
	gs->g2d_surface.base.format = g2dFormat;
}


static void
g2d_renderer_get_g2dformat_from_dmabuf(uint32_t dmaformat,
			enum g2d_format *g2dFormat, int *bpp)
{
	switch (dmaformat) {
		case DRM_FORMAT_ARGB8888:
			*g2dFormat = G2D_BGRA8888;
			*bpp = 4;
			break;
		case DRM_FORMAT_ABGR8888:
			*g2dFormat = G2D_RGBA8888;
			*bpp = 4;
			break;
		case DRM_FORMAT_XRGB8888:
			*g2dFormat = G2D_BGRX8888;
			*bpp = 4;
			break;
		case DRM_FORMAT_RGB565:
			*g2dFormat = G2D_RGB565;
			*bpp = 2;
			break;
		case DRM_FORMAT_YUYV:
			*g2dFormat = G2D_YUYV;
			*bpp = 2;
			break;
		case DRM_FORMAT_NV12:
			*g2dFormat = G2D_NV12;
			*bpp = 1;
			break;
		case DRM_FORMAT_YUV420:
			*g2dFormat = G2D_I420;
			*bpp = 1;
			break;
		default:
			*g2dFormat = -1;
			weston_log("warning: unknown dmabuf buffer format: %08x\n", dmaformat);
			break;
	}
}

static void
g2d_renderer_attach_dmabuf(struct weston_surface *es, struct  weston_buffer *buffer,
			struct linux_dmabuf_buffer *dmabuf)
{
	struct g2d_surface_state *gs = get_surface_state(es);
	int alignedWidth = 0, alignedHeight = 0;
	enum g2d_format g2dFormat;
	gctUINT32 *paddr;
	int i = 0;
	int bpp = 1;
	buffer->width = dmabuf->attributes.width;
	buffer->height = dmabuf->attributes.height;
	if(dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED) {
		alignedWidth  = ALIGN_TO_64(buffer->width);
		alignedHeight = ALIGN_TO_64(buffer->height);
	} else {
		alignedWidth  = ALIGN_TO_16(buffer->width);
		alignedHeight = ALIGN_TO_16(buffer->height);
	}
	g2d_renderer_get_g2dformat_from_dmabuf(dmabuf->attributes.format, &g2dFormat, &bpp);

	if (g2dFormat < 0)
		return;

	paddr = (gctUINT32 *)linux_dmabuf_buffer_get_user_data(dmabuf);
	for (i = 0; i < dmabuf->attributes.n_planes; i++) {
		gs->g2d_surface.base.planes[i] = paddr[i] + dmabuf->attributes.offset[i];
	}

	gs->g2d_surface.base.left = 0;
	gs->g2d_surface.base.top  = 0;
	gs->g2d_surface.base.right	= buffer->width;
	gs->g2d_surface.base.bottom = buffer->height;
	gs->g2d_surface.base.width	= alignedWidth;
	gs->g2d_surface.base.height = alignedHeight;
	gs->g2d_surface.base.rot	= G2D_ROTATION_0;
	if (dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_AMPHION_TILED) {
		gs->g2d_surface.base.stride = dmabuf->attributes.stride[0];
		gs->g2d_surface.tiling = G2D_AMPHION_TILED;
	} else if(dmabuf->attributes.modifier[0] == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED){
		gs->g2d_surface.base.stride = alignedWidth;
		gs->g2d_surface.tiling = G2D_SUPERTILED;
	} else {
		gs->g2d_surface.base.stride = dmabuf->attributes.stride[0] / bpp;
		gs->g2d_surface.tiling = G2D_LINEAR;
	}
	gs->g2d_surface.base.format = g2dFormat;
}

static void
g2d_renderer_query_dmabuf_formats(struct weston_compositor *wc,
			int **formats, int *num_formats)
{
	int num;
	static const int dma_formats[] = {
		DRM_FORMAT_ARGB8888,
		DRM_FORMAT_ABGR8888,
		DRM_FORMAT_XRGB8888,
		DRM_FORMAT_RGB565,
		DRM_FORMAT_YUYV,
		DRM_FORMAT_NV12,
		DRM_FORMAT_YUV420,
	};

	num = ARRAY_LENGTH(dma_formats);
	*formats = calloc(num, sizeof(int));
	memcpy(*formats, dma_formats, num * sizeof(int));

	*num_formats = num;
}

static void
g2d_renderer_query_dmabuf_modifiers(struct weston_compositor *wc, int format,
			uint64_t **modifiers,
			int *num_modifiers)
{
	*num_modifiers = 1;
	*modifiers = calloc(*num_modifiers, sizeof(uint64_t));
	(*modifiers)[0] = DRM_FORMAT_MOD_LINEAR;
}

static void
free_paddr_buf (struct linux_dmabuf_buffer *buffer)
{
	gctUINT32 * paddr = (gctUINT32 *)buffer->user_data;
	if (paddr)
		free (paddr);
}

static bool
g2d_renderer_import_dmabuf(struct weston_compositor *wc,
			struct linux_dmabuf_buffer *dmabuf)
{
	struct g2d_buf *g2dBuf = NULL;
	enum g2d_format g2dFormat;
	gctUINT32 *paddr = NULL;
	int i = 0, dmafd = -1;
	int bpp = 1;

	if (!dmabuf)
		return false;

	g2d_renderer_get_g2dformat_from_dmabuf(dmabuf->attributes.format, &g2dFormat, &bpp);
	if (g2dFormat < 0)
		return false;

	paddr = malloc (sizeof (gctUINT32) * dmabuf->attributes.n_planes);
	if (!paddr)
		return false;

	for (i = 0; i < dmabuf->attributes.n_planes; i++) {
		dmafd = dup(dmabuf->attributes.fd[i]);
		if (dmafd == -1)
			goto failed;

		if (g2dBuf)
			g2d_free(g2dBuf);
		g2dBuf = g2d_buf_from_fd(dmafd);
		if(!g2dBuf)
			goto failed;
		paddr[i] = g2dBuf->buf_paddr;
		close(dmafd);
	}

	if(!g2dBuf)
		return false;
	else
		g2d_free(g2dBuf);

	linux_dmabuf_buffer_set_user_data(dmabuf, (void *)paddr, free_paddr_buf);

	return true;

failed:
	if (paddr)
		free(paddr);

	if(g2dBuf)
		g2d_free(g2dBuf);

	if (dmafd != -1)
		close(dmafd);

	return false;
}

static void
g2d_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
{
	struct g2d_surface_state *gs = get_surface_state(es);
	struct wl_shm_buffer *shm_buffer;
	struct linux_dmabuf_buffer *dmabuf;
	weston_buffer_reference(&gs->buffer_ref, buffer);
	weston_buffer_release_reference(&gs->buffer_release_ref,
					es->buffer_release_ref.buffer_release);

	if (!buffer) {
		gs->attached = 0;
		return;
	}

	shm_buffer = wl_shm_buffer_get(buffer->resource);

	if(shm_buffer)
	{
		g2d_renderer_attach_shm(es, buffer, shm_buffer);
	}
	else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
	{
		g2d_renderer_attach_dmabuf(es, buffer, dmabuf);
	}
	else
	{
		g2d_renderer_attach_egl(es, buffer);
	}
	gs->attached = 1;
}

static void
surface_state_destroy(struct g2d_surface_state *gs, struct g2d_renderer *gr)
{
	wl_list_remove(&gs->surface_destroy_listener.link);
	wl_list_remove(&gs->renderer_destroy_listener.link);
	if(gs->surface)
		gs->surface->renderer_state = NULL;
	
	if(gs->shm_buf)
	{
		g2d_free(gs->shm_buf);
		gs->shm_buf = NULL;
	}
	if(gs->dma_buf)
	{
		g2d_free(gs->dma_buf);
		gs->dma_buf = NULL;
	}

	weston_buffer_reference(&gs->buffer_ref, NULL);
	weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
	free(gs);
}

static void
surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
{
	struct g2d_surface_state *gs;
	struct g2d_renderer *gr;

	gs = container_of(listener, struct g2d_surface_state,
			  surface_destroy_listener);

	gr = get_renderer(gs->surface->compositor);
	surface_state_destroy(gs, gr);
}

static void
surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
{
	struct g2d_surface_state *gs;
	struct g2d_renderer *gr;

	gr = data;

	gs = container_of(listener, struct g2d_surface_state,
			  renderer_destroy_listener);

	surface_state_destroy(gs, gr);
}


static int
g2d_renderer_create_surface(struct weston_surface *surface)
{
	struct g2d_surface_state *gs;
	struct g2d_renderer *gr = get_renderer(surface->compositor);

	gs = zalloc(sizeof *gs);
	if (gs == NULL)
		return -1;

	/* A buffer is never attached to solid color surfaces, yet
	 * they still go through texcoord computations. Do not divide
	 * by zero there.
	 */
	gs->pitch = 1;

	gs->surface = surface;

	pixman_region32_init(&gs->texture_damage);
	surface->renderer_state = gs;

	gs->surface_destroy_listener.notify =
		surface_state_handle_surface_destroy;
	wl_signal_add(&surface->destroy_signal,
			  &gs->surface_destroy_listener);

	gs->renderer_destroy_listener.notify =
		surface_state_handle_renderer_destroy;
	wl_signal_add(&gr->destroy_signal,
			  &gs->renderer_destroy_listener);

	if (surface->buffer_ref.buffer) {
		g2d_renderer_attach(surface, surface->buffer_ref.buffer);
		g2d_renderer_flush_damage(surface);
	}
	
	return 0;
}

static void
g2d_renderer_surface_set_color(struct weston_surface *surface,
		 float red, float green, float blue, float alpha)
{
	struct g2d_surface_state *gs = get_surface_state(surface);

	gs->color[0] = red;
	gs->color[1] = green;
	gs->color[2] = blue;
	gs->color[3] = alpha;
}

/* create use-g2d-renderer */
static void
create_g2d_file(struct weston_output *output)
{
	char *dir, *path;
	FILE *fp = NULL;

	dir = getenv("XDG_RUNTIME_DIR");
	path = malloc(strlen(dir) + 40);
	strcpy(path, dir);
	strcat(path, "/use-g2d-renderer");

	fp = fopen(path, "w");
	if(fp) {
		weston_log("Create File %s\n", path);

		if(output->transform == WL_OUTPUT_TRANSFORM_90
			|| output->transform == WL_OUTPUT_TRANSFORM_270) {
			fprintf(fp, "transform=1\n");
		}
		fclose(fp);
	}
	free(path);
}

static void
remove_g2d_file()
{
	char *dir, *path;

	dir = getenv("XDG_RUNTIME_DIR");
	path = malloc(strlen(dir) + 40);
	strcpy(path, dir);
	strcat(path, "/use-g2d-renderer");
	remove(path);
	free(path);
}

static void
g2d_renderer_output_destroy(struct weston_output *output)
{
	struct g2d_output_state *go = get_output_state(output);
	int i;

	for (i = 0; i < 2; i++)
	{
		pixman_region32_fini(&go->buffer_damage[i]);
	}

	if(go->offscreen_buf)
	{
		g2d_free(go->offscreen_buf);
		go->offscreen_buf = NULL;
	}

	if(go->fb_info.fb_fd)
	{
		close(go->fb_info.fb_fd);
		go->fb_info.fb_fd = 0;
	}

	if(go->renderSurf)
	{
		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;
	}

	fd_clear(&go->drm_hw_buffer->reserved[0]);

	remove_g2d_file();

	free(go);
}

static void
g2d_renderer_destroy(struct weston_compositor *ec)
{
	struct g2d_renderer *gr = get_renderer(ec);

	wl_signal_emit(&gr->destroy_signal, gr);
	g2d_close(gr->handle);
#ifdef ENABLE_EGL
	if(gr->bind_display)
		gr->bind_display(gr->egl_display, gr->wl_display);
	eglTerminate(gr->egl_display);
	if(!gr->use_drm)
		fbDestroyDisplay(gr->display);
#endif
	free(ec->renderer);
	ec->renderer = NULL;
}

static int
g2d_renderer_create(struct weston_compositor *ec)
{
	struct g2d_renderer *gr;

	gr = calloc(1, sizeof *gr);
	if (gr == NULL)
		return -1;

	gr->base.read_pixels = g2d_renderer_read_pixels;
	gr->base.repaint_output = g2d_renderer_repaint_output;
	gr->base.flush_damage = g2d_renderer_flush_damage;
	gr->base.attach = g2d_renderer_attach;
	gr->base.surface_set_color = g2d_renderer_surface_set_color;
	gr->base.destroy = g2d_renderer_destroy;
	gr->base.import_dmabuf = g2d_renderer_import_dmabuf;
	gr->base.query_dmabuf_formats = g2d_renderer_query_dmabuf_formats;
	gr->base.query_dmabuf_modifiers = g2d_renderer_query_dmabuf_modifiers;
	ec->renderer = &gr->base;
#ifdef ENABLE_EGL
	gr->bind_display =
		(void *) eglGetProcAddress("eglBindWaylandDisplayWL");
	gr->unbind_display =
		(void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
	gr->update_buffer =
		(void *) eglGetProcAddress("eglUpdateWaylandBufferWL");
	if (!get_platform_display)
	{
		get_platform_display = (void *) eglGetProcAddress(
				"eglGetPlatformDisplayEXT");
	}

	ec->capabilities |= WESTON_CAP_EXPLICIT_SYNC;
#endif
	if(g2d_open(&gr->handle))
	{
		weston_log("g2d_open fail.\n");
		return -1;
	}

	ec->capabilities |= WESTON_CAP_ROTATION_ANY;
	ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
	ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
	ec->read_format = PIXMAN_a8r8g8b8;

	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUV420);
	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_NV12);
	wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_YUYV);

	wl_signal_init(&gr->destroy_signal);

	return 0;
}

static int
g2d_drm_display_create(struct weston_compositor *ec, void *native_window)
{
	struct g2d_renderer *gr;
	if(g2d_renderer_create(ec) < 0)
	{
		weston_log("g2d_renderer_create faile.\n");
		return -1;
	}
#ifdef ENABLE_EGL
	gr = get_renderer(ec);
	gr->wl_display = ec->wl_display;
	if(get_platform_display)
		gr->egl_display = get_platform_display(EGL_PLATFORM_GBM_KHR,
				native_window, NULL);
	if(gr->bind_display)
		gr->bind_display(gr->egl_display, gr->wl_display);
#endif
	gr->use_drm = 1;

	return 0;
}

static void
g2d_renderer_output_set_buffer(struct weston_output *output, struct g2d_surfaceEx *buffer)
{
	struct g2d_output_state *go = get_output_state(output);
	go->drm_hw_buffer = buffer;
}

static int
g2d_renderer_get_surface_fence_fd(struct g2d_surfaceEx *buffer)
{
	return buffer->reserved[0];
}

static int
g2d_drm_renderer_output_create(struct weston_output *output)
{
	struct g2d_output_state *go;
	int i = 0;

	go = zalloc(sizeof *go);
	if (go == NULL)
		return -1;
	output->renderer_state = go;

	for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
		pixman_region32_init(&go->buffer_damage[i]);

	create_g2d_file(output);

	return 0;
 }

static int
drm_create_g2d_image(struct g2d_surfaceEx* g2dSurface,
				enum g2d_format g2dFormat,
				void *vaddr,
				int w, int h, int stride,
				int size,
				int dmafd)
{
	struct g2d_buf * buffer = NULL;

	buffer = g2d_buf_from_fd(dmafd);
	if (!buffer)
		return -1;

	buffer->buf_vaddr = vaddr;
	buffer->buf_size  = size;
	g2dSurface->base.planes[0] = buffer->buf_paddr;
	g2dSurface->base.left = 0;
	g2dSurface->base.top  = 0;
	g2dSurface->base.right	= w;
	g2dSurface->base.bottom = h;
	g2dSurface->base.stride = w;
	g2dSurface->base.width	= w;
	g2dSurface->base.height = h;
	g2dSurface->base.format = g2dFormat;
	g2dSurface->base.rot	= G2D_ROTATION_0;
	g2dSurface->base.clrcolor = 0xFF400000;
	g2dSurface->tiling = G2D_LINEAR;
	g2dSurface->reserved[0] = -1;

	return 0;
}

static int
calculate_g2d_format(struct fb_var_screeninfo *varinfo, enum g2d_format *g2dFormat)
{
	/* Get the color format. */
	switch (varinfo->green.length)
	{
		case 6:
			*g2dFormat= G2D_RGB565;
			break;

		case 8:
			if (varinfo->blue.offset == 0)
			{
				*g2dFormat = (varinfo->transp.length == 0) ? G2D_BGRX8888 : G2D_BGRA8888;
			}
			else
			{
				*g2dFormat = (varinfo->transp.length == 0) ? G2D_RGBX8888 : G2D_RGBA8888;
			}
			break;

		default:
			*g2dFormat = -1;
			break;
	}
	return 0;
}

static int
get_G2dSurface_from_screeninfo(struct fb_screeninfo *info, struct g2d_surfaceEx* g2dSurface)
{
	if(info && g2dSurface)
	{
		g2dSurface->base.planes[0] = info->physical;
		g2dSurface->base.left = 0;
		g2dSurface->base.top  = 0;
		g2dSurface->base.right	= info->x_resolution;
		g2dSurface->base.bottom = info->y_resolution;
		g2dSurface->base.stride = info->stride;
		g2dSurface->base.width	= info->x_resolution;
		g2dSurface->base.height = info->y_resolution;
		g2dSurface->base.format = info->pixel_format;
		g2dSurface->base.rot	= G2D_ROTATION_0;
		g2dSurface->base.clrcolor = 0xFF400000;
		g2dSurface->tiling = G2D_LINEAR;
		return 0;
	}
	return -1;
}

static int
fb_query_screen_info(struct g2d_output_state *output, int fd,
						struct fb_screeninfo *info)
{
	struct g2d_output_state *go = output;
	struct fb_var_screeninfo *varinfo = &info->varinfo;
	struct fb_fix_screeninfo *fixinfo = &info->fixinfo;

	/* Probe the device for screen information. */
	if (ioctl(fd, FBIOGET_VSCREENINFO, varinfo) < 0) {
		return -1;
	}

	if(go->nNumBuffers > 1){
		varinfo->yres_virtual = varinfo->yres * go->nNumBuffers;
		if (ioctl(fd, FBIOPUT_VSCREENINFO, varinfo) < 0)
			return -1;
	}

	if (ioctl(fd, FBIOGET_FSCREENINFO, fixinfo) < 0 ||
		ioctl(fd, FBIOGET_VSCREENINFO, varinfo) < 0){
		return -1;
	}
	/* Store the pertinent data. */
	info->x_resolution = varinfo->xres;
	info->y_resolution = varinfo->yres;
	info->physical = fixinfo->smem_start;
	info->buffer_length = fixinfo->smem_len;
	info->stride = fixinfo->line_length / (varinfo->bits_per_pixel >> 3);
	info->stride_bytes = fixinfo->line_length;
	calculate_g2d_format(varinfo, &info->pixel_format);

	if (info->pixel_format < 0) {
		weston_log("Frame buffer uses an unsupported format.\n");
		return -1;
	}

	return 0;
}

static int
fb_frame_buffer_open(struct g2d_output_state *output, const char *fb_dev,
						struct fb_screeninfo *screen_info)
{
	/* Open the frame buffer device. */
	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, screen_info->fb_fd, screen_info) < 0) {
		weston_log("Failed to get frame buffer info \n");

		close(screen_info->fb_fd);
		return -1;
	}

	return 0;
}

static void
getBufferNumber(struct g2d_output_state *go)
{
	char *p = NULL;
	p = getenv("FB_MULTI_BUFFER");
	if (p == gcvNULL)
	{
		go->nNumBuffers = BUFFER_DAMAGE_COUNT;
	}
	else
	{
		go->nNumBuffers = atoi(p);
		if (go->nNumBuffers < 2)
		{
			go->nNumBuffers  = 1;
		}
		else if(go->nNumBuffers >= BUFFER_DAMAGE_COUNT)
		{
			go->nNumBuffers = BUFFER_DAMAGE_COUNT;
			go->activebuffer = 1;
		}
	}
	weston_log("The number of the Framebuffer: %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.stride_bytes * go->fb_info.y_resolution;
	for(i = 0; i < go->nNumBuffers; i++)
	{
		get_G2dSurface_from_screeninfo(&go->fb_info, &go->renderSurf[i]);
		go->renderSurf[i].base.planes[0] = go->fb_info.physical
											+ (offset * i);
		g2d_clear(gr->handle, &go->renderSurf[i].base);
	}

	if(go->nNumBuffers == 1)
	{
		go->offscreenSurface = (go->renderSurf[go->activebuffer]);
		go->offscreen_buf = g2d_alloc(go->fb_info.buffer_length, 0);
		go->offscreenSurface.base.planes[0] = go->offscreen_buf->buf_paddr;
		g2d_clear(gr->handle, &go->offscreenSurface.base);
	}
	return 0;
}

static int
g2d_fbdev_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;

#ifdef ENABLE_EGL
	gr->wl_display = wl_display;
	gr->display = fbGetDisplay(wl_display);
	gr->egl_display = eglGetDisplay(gr->display);
	if(gr->bind_display)
		gr->bind_display(gr->egl_display, wl_display);
#endif
	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);
	if(go->renderSurf->base.format == G2D_RGB565)
		g2d_enable(gr->handle, G2D_DITHER);
	for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
		pixman_region32_init(&go->buffer_damage[i]);

	create_g2d_file(output);

	return 0;
 }

 WL_EXPORT struct g2d_renderer_interface g2d_renderer_interface = {
	.create = g2d_renderer_create,
	.drm_display_create  = g2d_drm_display_create,
	.drm_output_create   = g2d_drm_renderer_output_create,
	.fbdev_output_create = g2d_fbdev_renderer_output_create,
	.create_g2d_image    = drm_create_g2d_image,
	.output_set_buffer   = g2d_renderer_output_set_buffer,
	.output_destroy      = g2d_renderer_output_destroy,
	.get_surface_fence_fd = g2d_renderer_get_surface_fence_fd,
};
