[Glamor] [PATCH] Add the poly line draw feature for glamor.

He Junyan junyan.he at linux.intel.com
Fri Apr 13 08:53:07 PDT 2012


Sorry, some err in rebase.
V2 has been sent


> I have two comments on this patch.
>
> 1. For comparison two floats/int with ">" or"<" ops, you don't need to add a
> epsilon which is only needed when you want to check whether the two floats are
> equal to each other. And I simply some of you code remove some uncessary
> type cast.
>
> 2. One time draw one line segment is not efficient, you can accumulate all the lines and
> draw them all at one call toe glDrawArray.
>
> I fixed the comment 1 and paste the new version as below. please check it out.
> For 2, I discussed with you, and please refine them latter. Anyway,
> this patch is already much better than original fully fallback to CPU when
> draw diagonal poly_line.
>
> But just before I pushed this patch, I found regressions with XTS test.
> xts5/Xlib9/XDrawLines/XDrawLines (32/104): FAIL
> xts5/Xlib9/XDrawLines/XDrawLines (57/104): FAIL
>
> There are also two or three failures on XDrawLine, please check and fix
> the regressions. Thanks.
>
>> From f5c3e62c16d88b137691e4032c17a429d26a18dd Mon Sep 17 00:00:00 2001
> From: Junyan He<junyan.he at linux.intel.com>
> Date: Fri, 13 Apr 2012 02:29:03 +0800
> Subject: [PATCH] Add the poly line draw feature for glamor.
>
>   Add the poly line draw feature for glamor. This can avoid to
>   download the pixman to CPU and upload it to GPU after draw.
>   Now, just solid narrow line draw is supported, other styles
>   will still fallback.
>
> Signed-off-by: Junyan He<junyan.he at linux.intel.com>
> Signed-off-by: Zhigang Gong<zhigang.gong at linux.intel.com>
> ---
>   src/glamor.c           |    2 +
>   src/glamor_polylines.c |  298 ++++++++++++++++++++++++++++++++++++++++++++++--
>   src/glamor_priv.h      |    7 +-
>   3 files changed, 295 insertions(+), 12 deletions(-)
>
> diff --git a/src/glamor.c b/src/glamor.c
> index 9b1d425..0b0a1be 100644
> --- a/src/glamor.c
> +++ b/src/glamor.c
> @@ -399,6 +399,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
>   	glamor_init_putimage_shaders(screen);
>   	glamor_init_finish_access_shaders(screen);
>   	glamor_init_gradient_shader(screen);
> +	glamor_init_polylines_shader(screen);
>   	glamor_pixmap_init(screen);
>
>   	glamor_priv->flags = flags;
> @@ -427,6 +428,7 @@ glamor_release_screen_priv(ScreenPtr screen)
>   	glamor_fini_putimage_shaders(screen);
>   	glamor_fini_finish_access_shaders(screen);
>   	glamor_fini_gradient_shader(screen);
> +	glamor_fini_polylines_shader(screen);
>   	glamor_pixmap_fini(screen);
>   	free(glamor_priv);
>
> diff --git a/src/glamor_polylines.c b/src/glamor_polylines.c
> index 70dd6c1..b1facca 100644
> --- a/src/glamor_polylines.c
> +++ b/src/glamor_polylines.c
> @@ -28,11 +28,265 @@
>
>   #include "glamor_priv.h"
>
> +#define GLAMOR_LINE_SLOPE      0
> +#define GLAMOR_LINE_SLOPE_INV  1
> +#define GLAMOR_LINE_VER_HOR    2
> +
>   /** @file glamor_polylines.c
>    *
>    * GC PolyFillRect implementation, taken straight from fb_fill.c
>    */
>
> +void
> +glamor_init_polylines_shader(ScreenPtr screen)
> +{
> +	glamor_screen_private *glamor_priv;
> +	glamor_gl_dispatch *dispatch;
> +
> +	const char *polylines_vs =
> +	    "attribute vec4 v_position;"
> +	    "void main()\n"
> +	    "{\n"
> +	    "    gl_Position = v_position;\n"
> +	    "}\n";
> +
> +	const char *polylines_fs =
> +	    GLAMOR_DEFAULT_PRECISION
> +	    "uniform vec4 color;\n"
> +	    "void main()\n"
> +	    "{\n"
> +	    "    gl_FragColor = color;\n"
> +	    "}\n";
> +
> +	GLint fs_prog, vs_prog;
> +
> +	glamor_priv = glamor_get_screen_private(screen);
> +	dispatch =  glamor_get_dispatch(glamor_priv);
> +
> +	glamor_priv->polylines_prog = dispatch->glCreateProgram();
> +
> +	vs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER, polylines_vs);
> +	fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER, polylines_fs);
> +
> +	dispatch->glAttachShader(glamor_priv->polylines_prog, vs_prog);
> +	dispatch->glAttachShader(glamor_priv->polylines_prog, fs_prog);
> +
> +	dispatch->glBindAttribLocation(glamor_priv->polylines_prog,
> +	        GLAMOR_VERTEX_POS, "v_position");
> +	dispatch->glBindAttribLocation(glamor_priv->polylines_prog,
> +	        GLAMOR_VERTEX_SOURCE, "v_texcoord");
> +
> +	glamor_link_glsl_prog(dispatch, glamor_priv->polylines_prog);
> +
> +	glamor_put_dispatch(glamor_priv);
> +}
> +
> +void
> +glamor_fini_polylines_shader(ScreenPtr screen)
> +{
> +	glamor_screen_private *glamor_priv;
> +	glamor_gl_dispatch *dispatch;
> +
> +	glamor_priv = glamor_get_screen_private(screen);
> +	dispatch = glamor_get_dispatch(glamor_priv);
> +	dispatch->glDeleteProgram(glamor_priv->polylines_prog);
> +	glamor_put_dispatch(glamor_priv);
> +}
> +
> +static Bool
> +_glamor_draw_polylines(DrawablePtr drawable, GCPtr gc, int n_rect,
> +		       xRectangle* rects, int* line_modes)
> +{
> +	glamor_screen_private *glamor_priv;
> +	int xorg, yorg;
> +	int xoff, yoff;
> +	int fullX1, fullX2, fullY1, fullY2;
> +	int n;
> +	int region_num;
> +	register BoxPtr pbox;
> +	RegionPtr pClip = fbGetCompositeClip(gc);
> +	PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(drawable);
> +
> +	glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
> +
> +	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
> +		glamor_fallback("dest %p has no fbo.\n", dst_pixmap);
> +		return FALSE;
> +	}
> +
> +	glamor_priv = glamor_get_screen_private(drawable->pScreen);
> +
> +	xorg = drawable->x;
> +	yorg = drawable->y;
> +
> +	for (n = 0; n<  n_rect; n++) {
> +		assert(line_modes[n] == GLAMOR_LINE_VER_HOR
> +		       || line_modes[n] == GLAMOR_LINE_SLOPE
> +		       || line_modes[n] == GLAMOR_LINE_SLOPE_INV);
> +
> +		if (line_modes[n] == GLAMOR_LINE_VER_HOR) {
> +			gc->ops->PolyFillRect(drawable, gc, 1,&rects[n]);
> +			continue;
> +		}
> +
> +		fullX1 = rects[n].x + xorg;
> +		fullY1 = rects[n].y + yorg;
> +		fullX2 = fullX1 + rects[n].width;
> +		fullY2 = fullY1 + rects[n].height;
> +
> +		region_num = REGION_NUM_RECTS(pClip);
> +		pbox = REGION_RECTS(pClip);
> +
> +		while (region_num--) {
> +			float x1 = fullX1;
> +			float x2 = fullX2;
> +			float y1 = fullY1;
> +			float y2 = fullY2;
> +			GLfloat color[4];
> +			float vertices[8];
> +			float line_points[4];
> +			GLfloat xscale, yscale;
> +			glamor_gl_dispatch *dispatch;
> +			GLint uniform_color_location;
> +			int tex_width;
> +
> +			if (pbox->x1>  fullX1)
> +				x1 = pbox->x1;
> +			if (pbox->x2<  fullX2)
> +				x2 = pbox->x2;
> +			if (pbox->y1>  fullY1)
> +				y1 = pbox->y1;
> +			if (pbox->y2<  fullY2)
> +				y2 = pbox->y2;
> +
> +			if (x1>= x2 || y1>= y2) {
> +				DebugF("rect: (%d, %d) (%d, %d)   \tclipbox: (%d, %d) (%d, %d)\n"
> +				       "--->  result:  (%f, %f) (%f, %f)   clip out\n",
> +				       fullX1, fullY1, fullX2, fullY2,
> +				       pbox->x1, pbox->y1, pbox->x2, pbox->y2,
> +				       x1, y1, x2, y2);
> +				continue;
> +			}
> +
> +			/* The CapNotLast mode, last pix can not draw.
> +			   We decrease the X or Y based on the slope.*/
> +			if (gc->capStyle == CapNotLast&&  n == n_rect - 1&&
> +			     (rects[n].x != rects[2].x || rects[n].y != rects[1].y)) {
> +				if ((x2 - x1)>  (y2 - y1))
> +					x2--;
> +				else {
> +					if (line_modes[n] == GLAMOR_LINE_SLOPE)
> +						y2--;
> +					else
> +						y1++;
> +				}
> +			}
> +
> +			if (line_modes[n] == GLAMOR_LINE_SLOPE) {
> +				float slope;
> +				float new_x, new_y;
> +
> +				slope = (float)(fullY2 - fullY1) / (fullX2 - fullX1);
> +				if ((x1>  fullX1) || (y1>  fullY1)) {
> +					new_x = (y1 - fullY1) / slope + fullX1;
> +					new_y = (x1 - fullX1) * slope + fullY1;
> +					x1 = max(new_x, x1);
> +					y1 = max(new_y, y1);
> +				}
> +
> +				if ((fullX2>  x2) || (fullY2>  y2)) {
> +					new_x = (y2 - fullY1) / slope + fullX1;
> +					new_y = (y2 - fullY1) * slope + fullY1;
> +					x2 = min(new_x, x2);
> +					y2 = min(new_y, y2);
> +				}
> +			} else {//GLAMOR_LINE_SLOPE_INV
> +				float slope;
> +				float new_x, new_y;
> +
> +				slope = (float)(fullY1 - fullY2) / (fullX2 - fullX1);
> +				if ((x1>  fullX1) || (fullY2>  y2)) {
> +					new_x = (y2 - fullY2) / slope + fullX1;
> +					new_y = (x1 - fullX1) * slope +fullY1;
> +					x1 = max(new_x, x1);
> +					y2 = min(new_y, y2);
> +				}
> +
> +				if ((fullX2>  x2) || (y1>  fullY1)) {
> +					new_x = (y1 - fullY2) / slope + fullX1;
> +					new_y = (x2 - fullX1) * slope + fullY2;
> +					x2 = min(new_x, x2);
> +					y1 = max(new_y, y1);
> +				}
> +			}
> +
> +			DebugF("rect: (%d, %d) (%d, %d)   \tclipbox: (%d, %d) (%d, %d)\n"
> +			       "--->  result:  (%f, %f) (%f, %f)\n",
> +			       fullX1, fullY1, fullX2, fullY2,
> +			       pbox->x1, pbox->y1, pbox->x2, pbox->y2,
> +			       x1, y1, x2, y2);
> +
> +			pbox++;
> +
> +			/* Use shader to draw the lines. */
> +			glamor_get_drawable_deltas(drawable, dst_pixmap,&xoff,&yoff);
> +			x1 += xoff;
> +			x2 += xoff;
> +			y1 += yoff;
> +			y2 += yoff;
> +
> +			glamor_get_rgba_from_pixel(gc->fgPixel,
> +			&color[0],
> +			&color[1],
> +			&color[2],
> +			&color[3],
> +			        format_for_pixmap(dst_pixmap));
> +
> +			glamor_set_destination_pixmap_priv_nc(pixmap_priv);
> +			glamor_validate_pixmap(dst_pixmap);
> +
> +			dispatch = glamor_get_dispatch(glamor_priv);
> +			glamor_set_alu(dispatch, gc->alu);
> +
> +			dispatch->glUseProgram(glamor_priv->polylines_prog);
> +			uniform_color_location =
> +			    dispatch->glGetUniformLocation(glamor_priv->polylines_prog, "color");
> +			dispatch->glUniform4fv(uniform_color_location, 1, color);
> +
> +			dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
> +			        GL_FALSE, 2 * sizeof(float), line_points);
> +			dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
> +
> +			pixmap_priv_get_scale(pixmap_priv,&xscale,&yscale);
> +			glamor_set_normalize_vcoords(xscale, yscale, x1, y1, x2, y2,
> +			        glamor_priv->yInverted, vertices);
> +
> +			if (line_modes[n] == GLAMOR_LINE_SLOPE) {
> +				line_points[0] = vertices[0];
> +				line_points[1] = vertices[1];
> +				line_points[2] = vertices[4];
> +				line_points[3] = vertices[5];
> +			} else {//GLAMOR_LINE_SLOPE_INV
> +				line_points[0] = vertices[2];
> +				line_points[1] = vertices[3];
> +				line_points[2] = vertices[6];
> +				line_points[3] = vertices[7];
> +			}
> +			DEBUGF("Draw from: (%f, %f) to (%f, %f)\n",
> +			       line_points[0], line_points[1],
> +			       line_points[2], line_points[3]);
> +
> +			dispatch->glDrawArrays(GL_LINES, 0, 4);
> +			dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
> +			dispatch->glUseProgram(0);
> +			glamor_set_alu(dispatch, GXcopy);
> +			glamor_put_dispatch(glamor_priv);
> +		}
> +	}
> +	return TRUE;
> +}
> +
> +
>   /**
>    * glamor_poly_lines() checks if it can accelerate the lines as a group of
>    * horizontal or vertical lines (rectangles), and uses existing rectangle fill
> @@ -43,8 +297,10 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
>   		   DDXPointPtr points, Bool fallback)
>   {
>   	xRectangle *rects;
> +	int *line_modes;
>   	int x1, x2, y1, y2;
>   	int i;
> +	int all_diag;
>   	glamor_screen_private *glamor_priv;
>
>   	/* Don't try to do wide lines or non-solid fill style. */
> @@ -54,15 +310,18 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
>   		 */
>   		goto wide_line;
>   	}
> -	if (gc->lineStyle != LineSolid) {
> +	if (gc->lineStyle != LineSolid || gc->fillStyle != FillSolid) {
>   		glamor_fallback
> -		    ("non-solid fill line style %d\n",
> -		     gc->lineStyle);
> +		("non-solid fill line style %d, fill style %d\n",
> +		 gc->lineStyle, gc->fillStyle);
>   		goto fail;
>   	}
> +
>   	rects = malloc(sizeof(xRectangle) * (n - 1));
> +	line_modes = malloc(sizeof(int) * (n - 1));
>   	x1 = points[0].x;
>   	y1 = points[0].y;
> +	all_diag = 1;
>   	/* If we have any non-horizontal/vertical, fall back. */
>   	for (i = 0; i<  n - 1; i++) {
>   		if (mode == CoordModePrevious) {
> @@ -72,11 +331,19 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
>   			x2 = points[i + 1].x;
>   			y2 = points[i + 1].y;
>   		}
> +
>   		if (x1 != x2&&  y1 != y2) {
> -			free(rects);
> -			glamor_fallback("stub diagonal poly_line\n");
> -			goto fail;
> +			if ((x2 - x1) * (y2 - y1)>  0)
> +				line_modes[i] = GLAMOR_LINE_SLOPE;
> +			else
> +				line_modes[i] = GLAMOR_LINE_SLOPE_INV;
> +
> +			all_diag = 0;
> +			DEBUGF("Have diagonal poly_line\n");
> +		} else {
> +			line_modes[i] = GLAMOR_LINE_VER_HOR;
>   		}
> +
>   		if (x1<  x2) {
>   			rects[i].x = x1;
>   			rects[i].width = x2 - x1 + 1;
> @@ -95,14 +362,25 @@ _glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
>   		x1 = x2;
>   		y1 = y2;
>   	}
> -	gc->ops->PolyFillRect(drawable, gc, n - 1, rects);
> +
> +	if (all_diag) { /* Fast path, all use the fill rect.*/
> +		gc->ops->PolyFillRect(drawable, gc, n - 1, rects);
> +	} else {
> +		if (_glamor_draw_polylines(drawable, gc, n - 1,
> +		      rects, line_modes) == FALSE)
> +			free(rects);
> +			free(line_modes);
> +			goto fail;
> +	}
> +
>   	free(rects);
> +	free(line_modes);
>   	return TRUE;
>
> -      fail:
> +fail:
>   	if (!fallback
> -	&&  glamor_ddx_fallback_check_pixmap(drawable)
> -	&&  glamor_ddx_fallback_check_gc(gc))
> +	&&  glamor_ddx_fallback_check_pixmap(drawable)
> +	&&  glamor_ddx_fallback_check_gc(gc))
>   		return FALSE;
>
>   	glamor_priv = glamor_get_screen_private(drawable->pScreen);
> diff --git a/src/glamor_priv.h b/src/glamor_priv.h
> index 961af47..3403942 100644
> --- a/src/glamor_priv.h
> +++ b/src/glamor_priv.h
> @@ -233,6 +233,9 @@ typedef struct glamor_screen_private {
>   	GLint tile_prog;
>   	GLint tile_wh;
>
> +	/* polylines */
> +	GLint polylines_prog;
> +
>   	/* glamor gradient */
>   	GLint gradient_prog[GRADIENT_SHADER_COUNT];
>
> @@ -530,13 +533,13 @@ glamor_poly_fill_rect(DrawablePtr drawable,
>
>   /* glamor_polylines.c */
>   void
> -
>   glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
>   		  DDXPointPtr points);
> +void glamor_init_polylines_shader(ScreenPtr screen);
> +void glamor_fini_polylines_shader(ScreenPtr screen);
>
>   /* glamor_putimage.c */
>   void
> -
>   glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
>   		 int w, int h, int leftPad, int format, char *bits);
>   void glamor_init_putimage_shaders(ScreenPtr screen);


More information about the Glamor mailing list