summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2014-04-03 14:22:52 -0700
committerKeith Packard <keithp@keithp.com>2014-06-02 11:10:19 -0700
commitd595094a884b59d4ad03ab685629199a2070bd3c (patch)
treea28c3a45071d36d58bdf7646777f41b13c4d6911
parent2a6137255856485d1f7fa71dcb3b3f09fae2ff83 (diff)
glamor: Add accelerated stipple support
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. v4: Review comments from Eric: * Remove stray whitespace change * Avoid "large" pixmap for stipple by using GLAMOR_CREATE_NO_LARGE * Wrap to 80 columns v5: Don't crash when stipple damage tracker is destroyed The stipple damage tracker is automatically destroyed when the associated stipple pixmap is destroyed. When this happens, just clear the pointer from the GC rather than calling glamor_invalidate_stipple; that function would call DamageUnregister on the now invalid stipple damage pointer and crash. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
-rw-r--r--glamor/glamor_core.c59
-rw-r--r--glamor/glamor_priv.h5
-rw-r--r--glamor/glamor_program.c39
-rw-r--r--glamor/glamor_transform.c72
4 files changed, 157 insertions, 18 deletions
diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c
index 381961441..f94c1fb1e 100644
--- a/glamor/glamor_core.c
+++ b/glamor/glamor_core.c
@@ -326,6 +326,58 @@ 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_gc_private *gc_priv = glamor_get_gc_private(gc);
+
+ gc_priv->stipple_damage = NULL;
+ 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);
+ }
+}
+
static GCFuncs glamor_fixup_gc_funcs;
/**
@@ -410,6 +462,9 @@ 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.
@@ -444,6 +499,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);
}
@@ -467,6 +525,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 6480eb607..129eaaadf 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -567,6 +567,8 @@ typedef enum glamor_pixmap_status {
typedef struct {
PixmapPtr dash;
+ PixmapPtr stipple;
+ DamagePtr stipple_damage;
} glamor_gc_private;
extern DevPrivateKeyRec glamor_gc_private_key;
@@ -684,6 +686,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 f3d4477fb..1d0328f2b 100644
--- a/glamor/glamor_program.c
+++ b/glamor/glamor_program.c
@@ -51,42 +51,51 @@ 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);
+ 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 d6ba56421..c1df56018 100644
--- a/glamor/glamor_transform.c
+++ b/glamor/glamor_transform.c
@@ -198,6 +198,64 @@ 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, GLAMOR_CREATE_NO_LARGE);
+ 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 +263,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);
}