[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