[PATCH 06/13] glamor: Add accelerated stipple support

Keith Packard keithp at keithp.com
Mon May 5 15:02:13 PDT 2014


This copies the stipple to a 8bpp pixmap and uses that to paint the
texture from.

v2: Create deep stipple pixmap without GLAMOR_CREATE_FBO_NO_FBO

v3: Fix stipple origin sign (matches tiles now). Track changes
    to original stipple with damage. This isn't required by the
    X spec, but java appears to depend on it, so we'll just do it.
    When Glamor switches to 8bpp bitmaps, we'll be able to render
    directly from them and not need this anymore.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 glamor/glamor_core.c      | 58 ++++++++++++++++++++++++++++++++++++++++
 glamor/glamor_priv.h      |  5 ++++
 glamor/glamor_program.c   | 35 ++++++++++++++----------
 glamor/glamor_transform.c | 68 ++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 149 insertions(+), 17 deletions(-)

diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c
index 9d941d7..26eb867 100644
--- a/glamor/glamor_core.c
+++ b/glamor/glamor_core.c
@@ -326,6 +326,56 @@ GCOps glamor_gc_ops = {
     .PushPixels = glamor_push_pixels,
 };
 
+/*
+ * When the stipple is changed or drawn to, invalidate any
+ * cached copy
+ */
+static void
+glamor_invalidate_stipple(GCPtr gc)
+{
+    glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
+
+    if (gc_priv->stipple) {
+        if (gc_priv->stipple_damage)
+            DamageUnregister(gc_priv->stipple_damage);
+        glamor_destroy_pixmap(gc_priv->stipple);
+        gc_priv->stipple = NULL;
+    }
+}
+
+static void
+glamor_stipple_damage_report(DamagePtr damage, RegionPtr region,
+                             void *closure)
+{
+    GCPtr       gc = closure;
+
+    glamor_invalidate_stipple(gc);
+}
+
+static void
+glamor_stipple_damage_destroy(DamagePtr damage, void *closure)
+{
+    GCPtr       gc = closure;
+
+    glamor_invalidate_stipple(gc);
+}
+
+void
+glamor_track_stipple(GCPtr gc)
+{
+    if (gc->stipple) {
+        glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
+
+        if (!gc_priv->stipple_damage)
+            gc_priv->stipple_damage = DamageCreate(glamor_stipple_damage_report,
+                                                   glamor_stipple_damage_destroy,
+                                                   DamageReportNonEmpty,
+                                                   TRUE, gc->pScreen, gc);
+        if (gc_priv->stipple_damage)
+            DamageRegister(&gc->stipple->drawable, gc_priv->stipple_damage);
+    }
+}
+
 /**
  * uxa_validate_gc() sets the ops to glamor's implementations, which may be
  * accelerated or may sync the card and fall back to fb.
@@ -396,7 +446,11 @@ glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
         changes &= ~GCTile;
     }
 
+    if (changes & GCStipple)
+        glamor_invalidate_stipple(gc);
+
     if (changes & GCStipple && gc->stipple) {
+
         /* We can't inline stipple handling like we do for GCTile because
          * it sets fbgc privates.
          */
@@ -430,6 +484,9 @@ glamor_destroy_gc(GCPtr gc)
         glamor_destroy_pixmap(gc_priv->dash);
         gc_priv->dash = NULL;
     }
+    glamor_invalidate_stipple(gc);
+    if (gc_priv->stipple_damage)
+        DamageDestroy(gc_priv->stipple_damage);
     miDestroyGC(gc);
 }
 
@@ -453,6 +510,7 @@ glamor_create_gc(GCPtr gc)
     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
 
     gc_priv->dash = NULL;
+    gc_priv->stipple = NULL;
     if (!fbCreateGC(gc))
         return FALSE;
 
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index e438f7f..a26a758 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -570,6 +570,8 @@ typedef enum glamor_pixmap_status {
 
 typedef struct {
     PixmapPtr   dash;
+    PixmapPtr   stipple;
+    DamagePtr   stipple_damage;
 } glamor_gc_private;
 
 extern DevPrivateKeyRec glamor_gc_private_key;
@@ -687,6 +689,9 @@ Bool glamor_set_alu(ScreenPtr screen, unsigned char alu);
 Bool glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask);
 RegionPtr glamor_bitmap_to_region(PixmapPtr pixmap);
 
+void
+glamor_track_stipple(GCPtr gc);
+
 /* glamor_fill.c */
 Bool glamor_fill(DrawablePtr drawable,
                  GCPtr gc, int x, int y, int width, int height, Bool fallback);
diff --git a/glamor/glamor_program.c b/glamor/glamor_program.c
index 0e3e94d..ba9333e 100644
--- a/glamor/glamor_program.c
+++ b/glamor/glamor_program.c
@@ -51,42 +51,49 @@ static const glamor_facet glamor_fill_tile = {
     .use = use_tile,
 };
 
-#if 0
 static Bool
-use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog)
+use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
 {
     return glamor_set_stippled(pixmap, gc, prog->fg_uniform, prog->fill_offset_uniform, prog->fill_size_uniform);
 }
 
 static const glamor_facet glamor_fill_stipple = {
     .name = "stipple",
-    .version = 130,
-    .vs_exec =  "       fill_pos = fill_offset + primitive.xy + pos;\n";
-    .fs_exec = ("       if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
+    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) / fill_size;\n",
+    .fs_exec = ("       float a = texture2D(sampler, fill_pos).w;\n"
+                "       if (a == 0.0)\n"
                 "               discard;\n"
-                "       gl_FragColor = fg;\n")
-    .locations = glamor_program_location_fg | glamor_program_location_fill
+                "       gl_FragColor = fg;\n"),
+    .locations = glamor_program_location_fg | glamor_program_location_fill,
     .use = use_stipple,
 };
 
+static Bool
+use_opaque_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
+{
+    if (!use_stipple(pixmap, gc, prog, arg))
+        return FALSE;
+    glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
+    return TRUE;
+}
+
 static const glamor_facet glamor_fill_opaque_stipple = {
     .name = "opaque_stipple",
-    .version = 130,
-    .vs_exec =  "       fill_pos = fill_offset + primitive.xy + pos;\n";
-    .fs_exec = ("       if (texelFetch(sampler, ivec2(mod(fill_pos,fill_size)), 0).x == 0)\n"
+    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) / fill_size;\n",
+    .fs_exec = ("       float a = texture2D(sampler, fill_pos).w;\n"
+                "       if (a == 0.0)\n"
                 "               gl_FragColor = bg;\n"
                 "       else\n"
                 "               gl_FragColor = fg;\n"),
-    .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill
+    .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fill,
     .use = use_opaque_stipple
 };
-#endif
 
 static const glamor_facet *glamor_facet_fill[4] = {
     &glamor_fill_solid,
     &glamor_fill_tile,
-    NULL,
-    NULL,
+    &glamor_fill_stipple,
+    &glamor_fill_opaque_stipple,
 };
 
 typedef struct {
diff --git a/glamor/glamor_transform.c b/glamor/glamor_transform.c
index d6ba564..87f8dda 100644
--- a/glamor/glamor_transform.c
+++ b/glamor/glamor_transform.c
@@ -198,6 +198,60 @@ glamor_set_tiled(PixmapPtr      pixmap,
                               size_uniform);
 }
 
+static PixmapPtr
+glamor_get_stipple_pixmap(GCPtr gc)
+{
+    glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
+    ScreenPtr   screen = gc->pScreen;
+    PixmapPtr   bitmap;
+    PixmapPtr   pixmap;
+    GCPtr       scratch_gc;
+    ChangeGCVal changes[2];
+
+    if (gc_priv->stipple)
+        return gc_priv->stipple;
+
+    bitmap = gc->stipple;
+    if (!bitmap)
+        goto bail;
+
+    pixmap = glamor_create_pixmap(screen, bitmap->drawable.width, bitmap->drawable.height, 8, 0);
+    if (!pixmap)
+        goto bail;
+
+    scratch_gc = GetScratchGC(8, screen);
+    if (!scratch_gc)
+        goto bail_pixmap;
+
+    changes[0].val = 0xff;
+    changes[1].val = 0x00;
+    if (ChangeGC(NullClient, scratch_gc,
+                 GCForeground|GCBackground, changes) != Success)
+        goto bail_gc;
+    ValidateGC(&pixmap->drawable, scratch_gc);
+
+    (*scratch_gc->ops->CopyPlane)(&bitmap->drawable,
+                                  &pixmap->drawable,
+                                  scratch_gc,
+                                  0, 0,
+                                  bitmap->drawable.width, bitmap->drawable.height,
+                                  0, 0, 0x1);
+
+    FreeScratchGC(scratch_gc);
+    gc_priv->stipple = pixmap;
+
+    glamor_track_stipple(gc);
+
+    return pixmap;
+
+bail_gc:
+    FreeScratchGC(scratch_gc);
+bail_pixmap:
+    glamor_destroy_pixmap(pixmap);
+bail:
+    return NULL;
+}
+
 Bool
 glamor_set_stippled(PixmapPtr      pixmap,
                     GCPtr          gc,
@@ -205,11 +259,19 @@ glamor_set_stippled(PixmapPtr      pixmap,
                     GLint          offset_uniform,
                     GLint          size_uniform)
 {
-    if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
+    PixmapPtr   stipple;
+
+    stipple = glamor_get_stipple_pixmap(gc);
+    if (!stipple)
         return FALSE;
 
-    if (!glamor_set_texture(pixmap, gc->stipple, gc->patOrg.x, gc->patOrg.y, offset_uniform, size_uniform))
+    if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
         return FALSE;
 
-    return TRUE;
+    return glamor_set_texture(pixmap,
+                              stipple,
+                              -gc->patOrg.x,
+                              -gc->patOrg.y,
+                              offset_uniform,
+                              size_uniform);
 }
-- 
2.0.0.rc0



More information about the xorg-devel mailing list