From 8ec26f122305f350832a7b8f9c720ac8e2c0f855 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Tue, 21 Jan 2014 09:24:07 +0100
Subject: [PATCH] glamor: add 0.5.1+git

Glamor can accelerate 2D X operations using GL or GLES2.

Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
 .../recipes-graphics/xorg-driver/glamor/copy.patch |  226 +++++++++++++++++++
 .../xorg-driver/glamor/polylines.patch             |  238 ++++++++++++++++++++
 meta-oe/recipes-graphics/xorg-driver/glamor_git.bb |   25 ++
 3 files changed, 489 insertions(+)
 create mode 100644 meta-oe/recipes-graphics/xorg-driver/glamor/copy.patch
 create mode 100644 meta-oe/recipes-graphics/xorg-driver/glamor/polylines.patch
 create mode 100644 meta-oe/recipes-graphics/xorg-driver/glamor_git.bb

diff --git a/meta-oe/recipes-graphics/xorg-driver/glamor/copy.patch b/meta-oe/recipes-graphics/xorg-driver/glamor/copy.patch
new file mode 100644
index 0000000..0576aee
--- /dev/null
+++ b/meta-oe/recipes-graphics/xorg-driver/glamor/copy.patch
@@ -0,0 +1,226 @@
+From https://bugs.freedesktop.org/show_bug.cgi?id=71813
+
+Upstream-status: Submitted
+
+diff --git a/src/glamor_copyarea.c b/src/glamor_copyarea.c
+index 4e6f953..257fb5c 100644
+--- a/src/glamor_copyarea.c
++++ b/src/glamor_copyarea.c
+@@ -163,16 +163,37 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
+ 	src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+ 	dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+ 
++	glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
++					   &src_y_off);
++	glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
++				   &dst_y_off);
++
+ 	if (!src_pixmap_priv->base.gl_fbo) {
+ #ifndef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ 		glamor_delayed_fallback(dst->pScreen, "src has no fbo.\n");
+ 		return FALSE;
+ #else
+-		src_status = glamor_upload_pixmap_to_texture(src_pixmap);
+-		if (src_status != GLAMOR_UPLOAD_DONE)
+-			return FALSE;
+-
+-		src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
++		/* Optimize when the source doesn't have an FBO, just upload
++		   the data directly to the dest FBO */
++		int src_stride = src_pixmap->devKind;
++		int bpp = src_pixmap->drawable.bitsPerPixel;
++		CARD8 *src_data = NULL;
++		for (i = 0; i < nbox; i++) {
++			int x = box[i].x1 + dst_x_off;
++			int y = box[i].y1 + dst_y_off;
++			int w = box[i].x2 - box[i].x1;
++			int h = box[i].y2 - box[i].y1;
++			src_data = src_pixmap->devPrivate.ptr + (box[i].y1 + dy +
++								src_y_off) * src_stride +
++								(box[i].x1 + dx + src_x_off) * (bpp / 8);
++			if (!glamor_upload_sub_pixmap_to_texture(dst_pixmap,
++					x, y, w, h,
++					src_stride, src_data, 0)) {
++				ErrorF("Failed to upload the sub pixmap to dst\n");
++				return FALSE;
++			}
++		}
++		return TRUE;
+ #endif
+ 	}
+ 
+@@ -180,8 +201,6 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
+ 	pixmap_priv_get_dest_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
+ 	pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
+ 
+-	glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
+-				   &dst_y_off);
+ 
+ 	dispatch = glamor_get_dispatch(glamor_priv);
+ 
+@@ -192,11 +211,11 @@ glamor_copy_n_to_n_textured(DrawablePtr src,
+ 					vertices);
+ 	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ 
+-	glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
+-				   &src_y_off);
++
+ 	dx += src_x_off;
+ 	dy += src_y_off;
+ 
++
+ 	dispatch->glActiveTexture(GL_TEXTURE0);
+ 	dispatch->glBindTexture(GL_TEXTURE_2D,
+ 				src_pixmap_priv->base.fbo->tex);
+@@ -335,7 +354,7 @@ __glamor_copy_n_to_n(DrawablePtr src,
+ 			      * 4 >
+ 			      src_pixmap->drawable.width *
+ 			      src_pixmap->drawable.height)
+-		             || !(glamor_check_fbo_size(glamor_priv,
++				|| !(glamor_check_fbo_size(glamor_priv,
+ 					src_pixmap->drawable.width,
+ 					src_pixmap->drawable.height))))) {
+ 
+diff --git a/src/glamor_pixmap.c b/src/glamor_pixmap.c
+index 84694ec..68a9214 100644
+--- a/src/glamor_pixmap.c
++++ b/src/glamor_pixmap.c
+@@ -387,7 +387,7 @@ static void
+ __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
+ 				  GLenum format,
+ 				  GLenum type,
+-				  int x, int y, int w, int h,
++				  int x, int y, int w, int h, int stride,
+ 				  void *bits, int pbo)
+ {
+ 	glamor_screen_private *glamor_priv =
+@@ -395,6 +395,12 @@ __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
+ 	glamor_gl_dispatch *dispatch;
+ 	int non_sub = 0;
+ 	unsigned int iformat = 0;
++	int bpp = depth_for_type(type);
++	int alignment = bpp / 8;
++	if (stride == 0) {
++		alignment = 4;
++	}
++
+ 
+ 	dispatch = glamor_get_dispatch(glamor_priv);
+ 	if (*tex == 0) {
+@@ -412,11 +418,13 @@ __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
+ 				  GL_NEAREST);
+ 	dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ 				  GL_NEAREST);
+-	dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
++	dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+ 
+ 	if (bits == NULL)
+ 		dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
+ 				       pbo);
++
++	dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / alignment);
+ 	if (non_sub)
+ 		dispatch->glTexImage2D(GL_TEXTURE_2D,
+ 				       0, iformat, w, h, 0,
+@@ -428,6 +436,8 @@ __glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
+ 					  format, type,
+ 					  bits);
+ 
++	dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
++
+ 	if (bits == NULL)
+ 		dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ 	glamor_put_dispatch(glamor_priv);
+@@ -511,7 +521,7 @@ ready_to_upload:
+ 		assert(y + fbo_y_off + h <= pixmap_priv->base.fbo->height);
+ 		__glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->base.fbo->tex,
+ 						  format, type,
+-						  x + fbo_x_off, y + fbo_y_off, w, h,
++						  x + fbo_x_off, y + fbo_y_off, w, h, stride,
+ 						  bits, pbo);
+ 		return TRUE;
+ 	}
+@@ -542,7 +552,7 @@ ready_to_upload:
+ 	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ 	__glamor_upload_pixmap_to_texture(pixmap, &tex,
+ 					  format, type,
+-					  0, 0, w, h,
++					  0, 0, w, h, stride,
+ 					  bits, pbo);
+ 	dispatch->glActiveTexture(GL_TEXTURE0);
+ 	dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+@@ -807,7 +817,7 @@ glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
+ 	if (glamor_upload_sub_pixmap_to_texture(pixmap, 0, 0,
+ 						pixmap->drawable.width,
+ 						pixmap->drawable.height,
+-						pixmap->devKind,
++						0,
+ 						data, pbo))
+ 		ret = GLAMOR_UPLOAD_DONE;
+ 	else
+diff --git a/src/glamor_putimage.c b/src/glamor_putimage.c
+index 99f7ac6..c389685 100644
+--- a/src/glamor_putimage.c
++++ b/src/glamor_putimage.c
+@@ -300,13 +300,13 @@ _glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ 		}
+ 
+ 		glamor_upload_sub_pixmap_to_texture(temp_pixmap, 0, 0, w, h,
+-						    pixmap->devKind, bits, 0);
+-
++						   0, bits, 0);
+ 		glamor_copy_area(&temp_pixmap->drawable, drawable, gc, 0, 0, w, h, x, y);
+ 		glamor_destroy_pixmap(temp_pixmap);
+-	} else
++	} else {
+ 		glamor_upload_sub_pixmap_to_texture(pixmap, x + drawable->x + x_off, y + drawable->y + y_off,
+-						    w, h, PixmapBytePad(w, depth), bits, 0);
++								    w, h, 0, bits, 0);
++	}
+ 	ret = TRUE;
+ 	goto done;
+ 
+diff --git a/src/glamor_setspans.c b/src/glamor_setspans.c
+index 3d447b6..32fd8cf 100644
+--- a/src/glamor_setspans.c
++++ b/src/glamor_setspans.c
+@@ -69,7 +69,7 @@ _glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
+ 			if (x1 >= x2)
+ 				continue;
+ 			glamor_upload_sub_pixmap_to_texture(dest_pixmap, x1 + x_off,  y1 + y_off, x2 - x1, 1,
+-							    PixmapBytePad(widths[i], drawable->depth),
++							    0,
+ 							    drawpixels_src, 0);
+ 		}
+ 		drawpixels_src += PixmapBytePad(widths[i], drawable->depth);
+diff --git a/src/glamor_utils.h b/src/glamor_utils.h
+index d307838..cf0f1eb 100644
+--- a/src/glamor_utils.h
++++ b/src/glamor_utils.h
+@@ -880,6 +880,26 @@ format_for_depth(int depth)
+ 	}
+ }
+ 
++static inline int
++depth_for_type(GLenum type)
++{
++	switch (type) {
++	case GL_UNSIGNED_BYTE:
++		return 8;
++	case GL_UNSIGNED_INT_8_8_8_8:
++	case GL_UNSIGNED_INT_8_8_8_8_REV:
++	case GL_UNSIGNED_INT_2_10_10_10_REV:
++		return 32;
++	case GL_UNSIGNED_SHORT_5_6_5:
++	case GL_UNSIGNED_SHORT_5_6_5_REV:
++	case GL_UNSIGNED_SHORT_1_5_5_5_REV:
++	case GL_UNSIGNED_SHORT_4_4_4_4_REV:
++		return 16;
++	default:
++		return 0;
++	}
++}
++
+ static inline void
+ gl_iformat_for_depth(int depth, GLenum * format)
+ {
diff --git a/meta-oe/recipes-graphics/xorg-driver/glamor/polylines.patch b/meta-oe/recipes-graphics/xorg-driver/glamor/polylines.patch
new file mode 100644
index 0000000..671174b
--- /dev/null
+++ b/meta-oe/recipes-graphics/xorg-driver/glamor/polylines.patch
@@ -0,0 +1,238 @@
+From 88923bf1fc132e77da3b31289a7ba66a3047cdcd Mon Sep 17 00:00:00 2001
+From: Aaron Watry <awatry@gmail.com>
+Date: Thu, 9 Jan 2014 19:16:31 -0600
+Subject: [PATCH] polylines: Handle diagonal lines
+
+Split a diagonal line into 2 or more horizontal/vertical lines.
+
+We want to split the line into as small a number of segments as possible.
+
+E.g. line from (x,y) of (1,1)->(5,2) with a slope of .25 would be split into:
+(1,1)->(2,1), (3,2)->(5,2)
+
+This is basically an implementation of Bresenham's line algorithm but with
+FP instead of integers.
+
+If the line's horizontal-ish, then iterate over the x values, and
+every time the rounded y value changes, start a new rectangle.
+If abs(slope) is > 1, then iterate over the y values instead.
+If the slope is == 1, then we're basically stuck drawing a bunch of points.
+
+Partially Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=68524
+
+Signed-off-by: Aaron Watry <awatry@gmail.com>
+Upstream-status: Submitted
+---
+ src/glamor_polylines.c | 166 +++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 146 insertions(+), 20 deletions(-)
+
+diff --git a/src/glamor_polylines.c b/src/glamor_polylines.c
+index e723e95..8891d3f 100644
+--- a/src/glamor_polylines.c
++++ b/src/glamor_polylines.c
+@@ -33,6 +33,126 @@
+  * GC PolyFillRect implementation, taken straight from fb_fill.c
+  */
+ 
++static void _draw_line(xRectangle *rects, int rect, int x1, int y1, int x2, int y2){
++		rects[rect].x = x1 < x2 ? x1 : x2;
++		rects[rect].y = y1 < y2 ? y1 : y2;
++		rects[rect].width = abs(x1 - x2) + 1;
++		rects[rect].height = abs(y1 - y2) + 1;
++}
++
++static xRectangle *_emit_line(xRectangle *rects, int *rects_cnt, int *rect, int x1, int y1, int x2, int y2){
++	*rects_cnt += 1;
++	rects = realloc(rects, sizeof(xRectangle) * *rects_cnt);
++	_draw_line(rects, *rect, x1, y1, x2, y2);
++	*rect += 1;
++	return rects;
++}
++
++static void _init_points(int *last_x, int *last_y, int cur_x, int cur_y, int *last_start_x, int *last_start_y){
++		*last_x = *last_start_x = cur_x;
++		*last_y = *last_start_y = cur_y;
++}
++
++static xRectangle *_next_point(xRectangle *rects, int *rects_cnt, int *rect, int cur_x, int cur_y, int *last_x, int *last_y, int *last_start_x, int *last_start_y, int steep){
++	if ((steep && *last_x != cur_x) || (!steep && *last_y != cur_y)){
++		//emit a line from last_start_x,last_start_y to last_x,last_y
++		rects = _emit_line(rects, rects_cnt, rect, *last_start_x, *last_start_y, *last_x, *last_y);
++		*last_start_x = cur_x;
++		*last_start_y = cur_y;
++	}
++	*last_x = cur_x;
++	*last_y = cur_y;
++	return rects;
++}
++
++/**
++ * We need to split the line into as small a number of segments as
++ * possible.
++ *
++ * E.g. line from (x,y) of (1,1)->(5,2) with a slope of .25
++
++ * would be split into two lines:
++ * (1,1)->(2,1), (3,2)->(5,2)
++ *
++ * This is basically an implementation of Bresenham's line algorithm but with
++ * FP for now, since I'm lazy.
++ *
++ * If the line's horizontal-ish, then iterate over the x values, and
++ * every time the rounded y value changes, start a new rectangle.
++ * If abs(slope) is > 1, then iterate over the y values instead.
++ * If the slope is == 1, then we're basically stuck drawing a bunch of points.
++ *
++ * @param rects Allocated list of xRectangle storage. grows when line is split
++ * @param rect_cnt Number of elements allocated in list
++ * @param rect Current index in list. modified as needed when the line is split
++ * @param x1 - X Coordinate of first point in line
++ * @param y1 - Y Coordinate of first point in line
++ * @param x2 - X Coordinate of second point in line
++ * @param y2 - Y Coordinate of second point in line
++ * @return rects - reallocated as needed... grows 1 rectangle every time the line splits
++ */
++static xRectangle *_glamor_diagonal_line(xRectangle *rects, int *rect_cnt, int *rect, int x1, int y1, int x2, int y2){
++	float slope = (float)(y2-y1) / (float)(x2-x1);
++	int vert = fabs(slope) > 1;
++	int i;
++
++	int cur_x, cur_y; //Current point being processed
++	int last_x, last_y; //Last point that was processed
++	int last_start_x, last_start_y; //Last x,y of a started line
++
++	if (vert){
++		//If we're dealing with slope > 1, then swap the x/y coords to make the
++		//line more horizontal than vertical. Reduces looping code
++		int temp = x1;
++		x1 = y1;
++		y1 = temp;
++
++		temp = x2;
++		x2 = y2;
++		y2 = temp;
++
++		//and recalculate the slope.
++		slope = (float)(y2-y1) / (float)(x2-x1);
++	}
++	if (x1 > x2){
++		//And now, if the points go right to left, swap them.
++		int temp = x1;
++		x1 = x2;
++		x2 = temp;
++
++		temp = y1;
++		y1 = y2;
++		y2 = temp;
++	}
++	cur_x = x1;
++	cur_y = y1;
++
++	//Now just iterate over the range from x1 to x2 and calculate the y values
++	//When plotting the points, if (vert==true), then just swap the cur_x/cur_y values
++	if (vert)
++		_init_points(&last_x, &last_y, y1, x1, &last_start_x, &last_start_y);
++	else
++		_init_points(&last_x, &last_y, x1, y1, &last_start_x, &last_start_y);
++
++	for(i = 0; i <= x2-x1; i++){
++		cur_x = x1+i;
++		cur_y = y1 + round(((float)i)*slope);
++		if (vert)
++			rects = _next_point(rects, rect_cnt, rect, cur_y, cur_x, &last_x, &last_y, &last_start_x, &last_start_y, vert);
++		else
++			rects = _next_point(rects, rect_cnt, rect, cur_x, cur_y, &last_x, &last_y, &last_start_x, &last_start_y, vert);
++	}
++
++	//And now finalize the last line segment using the space that was originally
++	//allocated for a horizontal/vertical line slot.
++	if (vert)
++		_draw_line(rects, *rect, last_start_x, last_start_y, cur_y, cur_x);
++	else
++		_draw_line(rects, *rect, last_start_x, last_start_y, cur_x, cur_y);
++
++	return rects;
++}
++
+ /**
+  * glamor_poly_lines() checks if it can accelerate the lines as a group of
+  * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+@@ -44,7 +164,7 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ {
+ 	xRectangle *rects;
+ 	int x1, x2, y1, y2;
+-	int i;
++	int i, rect_cnt, rect;
+ 
+ 	/* Don't try to do wide lines or non-solid fill style. */
+ 	if (gc->lineWidth != 0) {
+@@ -59,11 +179,12 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ 		     gc->lineStyle);
+ 		goto fail;
+ 	}
+-	rects = malloc(sizeof(xRectangle) * (n - 1));
++	rect_cnt = n-1;
++	rects = malloc(sizeof(xRectangle) * rect_cnt);
+ 	x1 = points[0].x;
+ 	y1 = points[0].y;
+ 	/* If we have any non-horizontal/vertical, fall back. */
+-	for (i = 0; i < n - 1; i++) {
++	for (rect = i = 0; i < n - 1; i++, rect++) {
+ 		if (mode == CoordModePrevious) {
+ 			x2 = x1 + points[i + 1].x;
+ 			y2 = y1 + points[i + 1].y;
+@@ -72,29 +193,34 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ 			y2 = points[i + 1].y;
+ 		}
+ 		if (x1 != x2 && y1 != y2) {
+-			free(rects);
+-			glamor_fallback("stub diagonal poly_line\n");
+-			goto fail;
+-		}
+-		if (x1 < x2) {
+-			rects[i].x = x1;
+-			rects[i].width = x2 - x1 + 1;
+-		} else {
+-			rects[i].x = x2;
+-			rects[i].width = x1 - x2 + 1;
+-		}
+-		if (y1 < y2) {
+-			rects[i].y = y1;
+-			rects[i].height = y2 - y1 + 1;
++			//For a diagonal line, for every line segment after the first one
++			//in the line, we will bump rect_cnt and realloc rects
++			rects = _glamor_diagonal_line(rects, &rect_cnt, &rect, x1, y1, x2, y2);
++
++			//free(rects);
++			//glamor_fallback("stub diagonal poly_line\n");
++			//goto fail;
+ 		} else {
+-			rects[i].y = y2;
+-			rects[i].height = y1 - y2 + 1;
++			if (x1 < x2) {
++				rects[rect].x = x1;
++				rects[rect].width = x2 - x1 + 1;
++			} else {
++				rects[rect].x = x2;
++				rects[rect].width = x1 - x2 + 1;
++			}
++			if (y1 < y2) {
++				rects[rect].y = y1;
++				rects[rect].height = y2 - y1 + 1;
++			} else {
++				rects[rect].y = y2;
++				rects[rect].height = y1 - y2 + 1;
++			}
+ 		}
+ 
+ 		x1 = x2;
+ 		y1 = y2;
+ 	}
+-	gc->ops->PolyFillRect(drawable, gc, n - 1, rects);
++	gc->ops->PolyFillRect(drawable, gc, rect_cnt, rects);
+ 	free(rects);
+ 	return TRUE;
+ 
+-- 
+1.8.3.2
+
diff --git a/meta-oe/recipes-graphics/xorg-driver/glamor_git.bb b/meta-oe/recipes-graphics/xorg-driver/glamor_git.bb
new file mode 100644
index 0000000..471df6c
--- /dev/null
+++ b/meta-oe/recipes-graphics/xorg-driver/glamor_git.bb
@@ -0,0 +1,25 @@
+require recipes-graphics/xorg-driver/xorg-driver-video.inc
+DESCRIPTION = "X.Org X server -- OpenGL based 2D rendering acceleration library"
+
+DEPENDS += "libdrm"
+
+LIC_FILES_CHKSUM = "file://COPYING;md5=c7f5e33031114ad132cb03949d73a8a8"
+
+PV = "0.5.1+gitr${SRCPV}"
+SRCREV = "2ac2fc0de978ba7076ba7c5e3c34caec05939dde"
+
+SRC_URI = "git://anongit.freedesktop.org/xorg/driver/glamor \
+           file://copy.patch \
+           file://polylines.patch \
+          "
+
+S = "${WORKDIR}/git"
+
+PACKAGECONFIG ??= "gl"
+
+PACKAGECONFIG[gl] = "--disable-glamor-gles2,,virtual/libgl"
+PACKAGECONFIG[gles2] = "--enable-glamor-gles2,,virtual/libgles2"
+
+FILES_${PN} += "${datadir}/X11 ${libdir}/xorg"
+FILES_${PN}-dbg += "${libdir}/xorg/modules/.debug"
+
-- 
1.7.10

