diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index 31cf3dce6..bafc42052 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); + } +} + /** * 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; 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) { + 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); }