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>
This commit is contained in:
Keith Packard 2014-04-03 14:22:52 -07:00 committed by Eric Anholt
parent d18f5801c9
commit bd3b2c48f6
4 changed files with 158 additions and 19 deletions

View File

@ -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);
}
}
/**
* 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,6 +448,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.
@ -430,6 +485,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 +511,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;

View File

@ -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);

View File

@ -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 {

View File

@ -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)
{
PixmapPtr stipple;
stipple = glamor_get_stipple_pixmap(gc);
if (!stipple)
return FALSE;
if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
return FALSE;
if (!glamor_set_texture(pixmap, gc->stipple, gc->patOrg.x, gc->patOrg.y, offset_uniform, size_uniform))
return FALSE;
return TRUE;
return glamor_set_texture(pixmap,
stipple,
-gc->patOrg.x,
-gc->patOrg.y,
offset_uniform,
size_uniform);
}