[PATCH xserver] glamor: Paint first and last pixel of lines

Max Staudt mstaudt at suse.de
Tue Feb 7 15:50:00 UTC 2017


OpenGL implementations are allowed to be imprecise in drawing line caps.
This patch expands on the original workaround in dc9fa908.

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=99705
Signed-off-by: Max Staudt <mstaudt at suse.de>
---
 glamor/glamor_lines.c | 21 +++++++++------------
 glamor/glamor_segs.c  | 43 ++++++++++++++++++++++++-------------------
 2 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/glamor/glamor_lines.c b/glamor/glamor_lines.c
index ca3cccf..47f8ed2 100644
--- a/glamor/glamor_lines.c
+++ b/glamor/glamor_lines.c
@@ -45,7 +45,6 @@ glamor_poly_lines_gl(DrawablePtr drawable, GCPtr gc,
     DDXPointPtr v;
     char *vbo_offset;
     int box_x, box_y;
-    int add_last;
 
     pixmap_priv = glamor_get_pixmap_private(pixmap);
     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
@@ -57,10 +56,6 @@ glamor_poly_lines_gl(DrawablePtr drawable, GCPtr gc,
     if (gc->lineStyle != LineSolid)
         goto bail;
 
-    add_last = 0;
-    if (gc->capStyle != CapNotLast)
-        add_last = 1;
-
     if (n < 2)
         return TRUE;
 
@@ -76,7 +71,7 @@ glamor_poly_lines_gl(DrawablePtr drawable, GCPtr gc,
     /* Set up the vertex buffers for the points */
 
     v = glamor_get_vbo_space(drawable->pScreen,
-                             (n + add_last) * sizeof (DDXPointRec),
+                             n * sizeof (DDXPointRec),
                              &vbo_offset);
 
     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
@@ -96,11 +91,6 @@ glamor_poly_lines_gl(DrawablePtr drawable, GCPtr gc,
         memcpy(v, points, n * sizeof (DDXPointRec));
     }
 
-    if (add_last) {
-        v[n].x = v[n-1].x + 1;
-        v[n].y = v[n-1].y;
-    }
-
     glamor_put_vbo_space(screen);
 
     glEnable(GL_SCISSOR_TEST);
@@ -118,7 +108,14 @@ glamor_poly_lines_gl(DrawablePtr drawable, GCPtr gc,
                       box->x2 - box->x1,
                       box->y2 - box->y1);
             box++;
-            glDrawArrays(GL_LINE_STRIP, 0, n + add_last);
+            glDrawArrays(GL_LINE_STRIP, 0, n);
+
+            /* Draw the first and last pixels, as implementations are
+             * allowed to be inaccurate there. */
+            if (gc->capStyle == CapNotLast)
+                glDrawArrays(GL_POINTS, 0, n-1);
+            else
+                glDrawArrays(GL_POINTS, 0, n);
         }
     }
 
diff --git a/glamor/glamor_segs.c b/glamor/glamor_segs.c
index 0168d05..b571b10 100644
--- a/glamor/glamor_segs.c
+++ b/glamor/glamor_segs.c
@@ -45,7 +45,6 @@ glamor_poly_segment_gl(DrawablePtr drawable, GCPtr gc,
     xSegment *v;
     char *vbo_offset;
     int box_x, box_y;
-    int add_last;
 
     pixmap_priv = glamor_get_pixmap_private(pixmap);
     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
@@ -57,10 +56,6 @@ glamor_poly_segment_gl(DrawablePtr drawable, GCPtr gc,
     if (gc->lineStyle != LineSolid)
         goto bail;
 
-    add_last = 0;
-    if (gc->capStyle != CapNotLast)
-        add_last = 1;
-
     glamor_make_current(glamor_priv);
 
     prog = glamor_use_program_fill(pixmap, gc,
@@ -71,27 +66,25 @@ glamor_poly_segment_gl(DrawablePtr drawable, GCPtr gc,
         goto bail_ctx;
 
     /* Set up the vertex buffers for the points */
-
+    /* We need 1.5 times the space in case of CapNotLast,
+     * so let's just always allocate 2 times the space. */
     v = glamor_get_vbo_space(drawable->pScreen,
-                             (nseg << add_last) * sizeof (xSegment),
+                             nseg * sizeof (xSegment) * 2,
                              &vbo_offset);
 
     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
                           sizeof(DDXPointRec), vbo_offset);
 
-    if (add_last) {
-        int i, j;
-        for (i = 0, j=0; i < nseg; i++) {
-            v[j++] = segs[i];
-            v[j].x1 = segs[i].x2;
-            v[j].y1 = segs[i].y2;
-            v[j].x2 = segs[i].x2+1;
-            v[j].y2 = segs[i].y2;
-            j++;
+    memcpy(v, segs, nseg * sizeof (xSegment));
+
+    /* In case of CapNotLast, copy the line starting points for later */
+    if (gc->capStyle != CapNotLast) {
+        int i;
+        for (i = 0; i < nseg; i++) {
+            v[2*nseg + i] = v[2*i];
         }
-    } else
-        memcpy(v, segs, nseg * sizeof (xSegment));
+    }
 
     glamor_put_vbo_space(screen);
 
@@ -110,7 +103,19 @@ glamor_poly_segment_gl(DrawablePtr drawable, GCPtr gc,
                       box->x2 - box->x1,
                       box->y2 - box->y1);
             box++;
-            glDrawArrays(GL_LINES, 0, nseg << (1 + add_last));
+            glDrawArrays(GL_LINES, 0, nseg * 2);
+
+            /* Draw the first and last pixel of each line, as OpenGL
+             * implementations are allowed to be inaccurate there.
+             * Since we're drawing all line ends, we can just reuse
+             * the array of all line starts and ends. */
+            if (gc->capStyle != CapNotLast) {
+                glDrawArrays(GL_POINTS, 0, nseg * 2);
+            } else {
+                /* With CapNotLast, we only want to draw the starting points.
+                 * That's why we copied them earlier. */
+                glDrawArrays(GL_POINTS, nseg, nseg);
+            }
         }
     }
 
-- 
2.10.2



More information about the xorg-devel mailing list