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

junyan.he at linux.intel.com junyan.he at linux.intel.com
Thu Apr 12 11:29:03 PDT 2012


From: Junyan He <junyan.he at linux.intel.com>

 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>
---
 src/glamor.c           |    2 +
 src/glamor_polylines.c |  298 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/glamor_priv.h      |    9 +-
 3 files changed, 296 insertions(+), 13 deletions(-)

diff --git a/src/glamor.c b/src/glamor.c
index 9b1d425..0b0a1be
--- 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..bb7e216
--- 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 = (float)fullX1;
+			float x2 = (float)fullX2;
+			float y1 = (float)fullY1;
+			float y2 = (float)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 = (float)pbox->x1;
+			if (pbox->x2 < fullX2)
+				x2 = (float)pbox->x2;
+			if (pbox->y1 > fullY1)
+				y1 = (float)pbox->y1;
+			if (pbox->y2 < fullY2)
+				y2 = (float)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) {
+				if ((x1 - fullX1 > 0.0001) || (y1 - fullY1 > 0.0001)) {
+					float new_x1 = ((float)((y1 - fullY1) * (fullX2 - fullX1)) /
+					                ((float)(fullY2 - fullY1))) + fullX1;
+					float new_y1 = ((float)((fullY2 - fullY1) * (x1 - fullX1)) /
+					                ((float)(fullX2 - fullX1))) + fullY1;
+					x1 = max(new_x1, x1);
+					y1 = max(new_y1, y1);
+				}
+
+				if ((fullX2 - x2 > 0.0001) || (fullY2 - y2 > 0.0001)) {
+					float new_x2 = ((float)((y2 - fullY1) * (fullX2 - fullX1)) /
+					                ((float)(fullY2 - fullY1))) + fullX1;
+					float new_y2 = ((float)((fullY2 - fullY1) * (x2 - fullX1)) /
+					                ((float)(fullX2 - fullX1))) + fullY1;
+					x2 = min(new_x2, x2);
+					y2 = min(new_y2, y2);
+				}
+			} else {//GLAMOR_LINE_SLOPE_INV
+				if ((x1 - fullX1 > 0.0001) || (fullY2 - y2 > 0.0001)) {
+					float new_x1 = ((float)((y2 - fullY2) * (fullX2 - fullX1)) /
+					                ((float)(fullY1 - fullY2))) + fullX1;
+					float new_y2 = ((float)((fullY1 - fullY2) * (x1 - fullX1)) /
+					                ((float)(fullX2 - fullX1))) + fullY2;
+					x1 = max(new_x1, x1);
+					y2 = min(new_y2, y2);
+				}
+
+				if ((fullX2 - x2 > 0.0001) || (y1 - fullY1 > 0.0001)) {
+					float new_x2 = ((float)((y1 - fullY2) * (fullX2 - fullX1)) /
+					                ((float)(fullY1 - fullY2))) + fullX1;
+					float new_y1 = ((float)((fullY1 - fullY2) * (x2 - fullX1)) /
+					                ((float)(fullX2 - fullX1))) + fullY2;
+					x2 = min(new_x2, x2);
+					y1 = max(new_y1, 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 += (float)xoff;
+			x2 += (float)xoff;
+			y1 += (float)yoff;
+			y2 += (float)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 f89632c..d343832
--- 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];
 
@@ -529,14 +532,14 @@ glamor_poly_fill_rect(DrawablePtr drawable,
 		      GCPtr gc, int nrect, xRectangle * prect);
 
 /* glamor_polylines.c */
-void
-
+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);
-- 
1.7.7.6



More information about the Glamor mailing list