From fa0fefd638d148d48760c95fe05520cddd96e5a4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 3 Nov 2011 15:33:25 +0000 Subject: [PATCH] sna: Restore the lowlevel glyph routines for the sake of Damage Damage bypasses the Text interface, preventing the backend from hooking into the font and storing private glyph representations, and calls directly into the Glyph routines. So to prevent a segfault we have to restore them. Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 305 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 303 insertions(+), 2 deletions(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 397a2d87..a2e9dc24 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -7352,6 +7352,307 @@ fallback: } } +/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */ +static bool +sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, + int _x, int _y, unsigned int _n, + CharInfoPtr *_info, pointer _base, + struct sna_damage **damage, + RegionPtr clip, + bool transparent) +{ + struct sna *sna = to_sna_from_drawable(drawable); + PixmapPtr pixmap = get_drawable_pixmap(drawable); + struct sna_pixmap *priv = sna_pixmap(pixmap); + const BoxRec *extents, *last_extents; + uint32_t *b; + int16_t dx, dy; + uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; + + if (priv->gpu_bo->tiling == I915_TILING_Y) { + DBG(("%s -- fallback, dst uses Y-tiling\n", __FUNCTION__)); + return false; + } + + get_drawable_deltas(drawable, pixmap, &dx, &dy); + _x += drawable->x + dx; + _y += drawable->y + dy; + + RegionTranslate(clip, dx, dy); + extents = REGION_RECTS(clip); + last_extents = extents + REGION_NUM_RECTS(clip); + + kgem_set_mode(&sna->kgem, KGEM_BLT); + if (!kgem_check_batch(&sna->kgem, 16) || + !kgem_check_bo_fenced(&sna->kgem, priv->gpu_bo, NULL) || + !kgem_check_reloc(&sna->kgem, 1)) { + _kgem_submit(&sna->kgem); + _kgem_set_mode(&sna->kgem, KGEM_BLT); + } + b = sna->kgem.batch + sna->kgem.nbatch; + b[0] = XY_SETUP_BLT | 1 << 20; + b[1] = priv->gpu_bo->pitch; + if (sna->kgem.gen >= 40) { + if (priv->gpu_bo->tiling) + b[0] |= BLT_DST_TILED; + b[1] >>= 2; + } + b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; + b[2] = extents->y1 << 16 | extents->x1; + b[3] = extents->y2 << 16 | extents->x2; + b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, + priv->gpu_bo, + I915_GEM_DOMAIN_RENDER << 16 | + I915_GEM_DOMAIN_RENDER | + KGEM_RELOC_FENCED, + 0); + b[5] = gc->bgPixel; + b[6] = gc->fgPixel; + b[7] = 0; + sna->kgem.nbatch += 8; + + do { + CharInfoPtr *info = _info; + int x = _x, y = _y, n = _n; + + do { + CharInfoPtr c = *info++; + uint8_t *glyph = FONTGLYPHBITS(base, c); + int w = GLYPHWIDTHPIXELS(c); + int h = GLYPHHEIGHTPIXELS(c); + int stride = GLYPHWIDTHBYTESPADDED(c); + int w8 = (w + 7) >> 3; + int x1, y1, len, i; + uint8_t *byte; + + if (w == 0 || h == 0) + goto skip; + + len = (w8 * h + 7) >> 3 << 1; + DBG(("%s glyph: (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, + x,y, w, w8, h, len)); + + x1 = x + c->metrics.leftSideBearing; + y1 = y - c->metrics.ascent; + + if (x1 >= extents->x2 || y1 >= extents->y2) + goto skip; + if (x1 + w <= extents->x1 || y1 + h <= extents->y1) + goto skip; + + if (!kgem_check_batch(&sna->kgem, 3+len)) { + _kgem_submit(&sna->kgem); + _kgem_set_mode(&sna->kgem, KGEM_BLT); + + b = sna->kgem.batch + sna->kgem.nbatch; + b[0] = XY_SETUP_BLT | 1 << 20; + b[1] = priv->gpu_bo->pitch; + if (sna->kgem.gen >= 40) { + if (priv->gpu_bo->tiling) + b[0] |= BLT_DST_TILED; + b[1] >>= 2; + } + b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; + b[2] = extents->y1 << 16 | extents->x1; + b[3] = extents->y2 << 16 | extents->x2; + b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, + priv->gpu_bo, + I915_GEM_DOMAIN_RENDER << 16 | + I915_GEM_DOMAIN_RENDER | + KGEM_RELOC_FENCED, + 0); + b[5] = gc->bgPixel; + b[6] = gc->fgPixel; + b[7] = 0; + sna->kgem.nbatch += 8; + } + + b = sna->kgem.batch + sna->kgem.nbatch; + sna->kgem.nbatch += 3 + len; + + b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len); + if (priv->gpu_bo->tiling && sna->kgem.gen >= 40) + b[0] |= BLT_DST_TILED; + b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; + b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); + + byte = (uint8_t *)&b[3]; + stride -= w8; + do { + i = w8; + do { + *byte++ = byte_reverse(*glyph++); + } while (--i); + glyph += stride; + } while (--h); + while ((byte - (uint8_t *)&b[3]) & 7) + *byte++ = 0; + assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch); + + if (damage) { + BoxRec r; + + r.x1 = x1; + r.y1 = y1; + r.x2 = x1 + w; + r.y2 = y1 + h; + if (box_intersect(&r, extents)) + sna_damage_add_box(damage, &r); + } +skip: + x += c->metrics.characterWidth; + } while (--n); + + if (++extents == last_extents) + break; + + if (kgem_check_batch(&sna->kgem, 3)) { + b = sna->kgem.batch + sna->kgem.nbatch; + sna->kgem.nbatch += 3; + + b[0] = XY_SETUP_CLIP; + b[1] = extents->y1 << 16 | extents->x1; + b[2] = extents->y2 << 16 | extents->x2; + } + } while (1); + + sna->blt_state.fill_bo = 0; + return true; +} + +static void +sna_image_glyph(DrawablePtr drawable, GCPtr gc, + int x, int y, unsigned int n, + CharInfoPtr *info, pointer base) +{ + struct sna *sna = to_sna_from_drawable(drawable); + ExtentInfoRec extents; + RegionRec region; + struct sna_damage **damage; + + if (n == 0) + return; + + QueryGlyphExtents(gc->font, info, n, &extents); + region.extents.x1 = x + extents.overallLeft; + region.extents.y1 = y - extents.overallAscent; + region.extents.x2 = x + extents.overallRight; + region.extents.y2 = y + extents.overallDescent; + + translate_box(®ion.extents, drawable); + clip_box(®ion.extents, gc); + if (box_empty(®ion.extents)) + return; + + DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, + region.extents.x1, region.extents.y1, + region.extents.x2, region.extents.y2)); + + if (FORCE_FALLBACK) + goto fallback_clip; + + if (wedged(sna)) { + DBG(("%s: fallback -- wedged\n", __FUNCTION__)); + goto fallback_clip; + } + + region.data = NULL; + region_maybe_clip(®ion, gc->pCompositeClip); + if (!RegionNotEmpty(®ion)) + return; + + if (sna_drawable_use_gpu_bo(drawable, ®ion.extents, &damage) && + sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, + damage, ®ion, false)) { + RegionUninit(®ion); + return; + } + +fallback: + DBG(("%s: fallback\n", __FUNCTION__)); + sna_gc_move_to_cpu(gc, drawable); + sna_drawable_move_region_to_cpu(drawable, ®ion, true); + RegionUninit(®ion); + + DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); + fbImageGlyphBlt(drawable, gc, x, y, n, info, base); + return; + +fallback_clip: + region.data = NULL; + region_maybe_clip(®ion, gc->pCompositeClip); + if (!RegionNotEmpty(®ion)) + return; + + goto fallback; +} + +static void +sna_poly_glyph(DrawablePtr drawable, GCPtr gc, + int x, int y, unsigned int n, + CharInfoPtr *info, pointer base) +{ + struct sna *sna = to_sna_from_drawable(drawable); + ExtentInfoRec extents; + RegionRec region; + struct sna_damage **damage; + + if (n == 0) + return; + + QueryGlyphExtents(gc->font, info, n, &extents); + region.extents.x1 = x + extents.overallLeft; + region.extents.y1 = y - extents.overallAscent; + region.extents.x2 = x + extents.overallRight; + region.extents.y2 = y + extents.overallDescent; + + translate_box(®ion.extents, drawable); + clip_box(®ion.extents, gc); + if (box_empty(®ion.extents)) + return; + + DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, + region.extents.x1, region.extents.y1, + region.extents.x2, region.extents.y2)); + + if (FORCE_FALLBACK) + goto fallback_clip; + + if (wedged(sna)) { + DBG(("%s: fallback -- wedged\n", __FUNCTION__)); + goto fallback_clip; + } + + region.data = NULL; + region_maybe_clip(®ion, gc->pCompositeClip); + if (!RegionNotEmpty(®ion)) + return; + + if (sna_drawable_use_gpu_bo(drawable, ®ion.extents, &damage) && + sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, + damage, ®ion, true)) { + RegionUninit(®ion); + return; + } + +fallback: + DBG(("%s: fallback\n", __FUNCTION__)); + sna_gc_move_to_cpu(gc, drawable); + sna_drawable_move_region_to_cpu(drawable, ®ion, true); + RegionUninit(®ion); + + DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); + fbPolyGlyphBlt(drawable, gc, x, y, n, info, base); + +fallback_clip: + region.data = NULL; + region_maybe_clip(®ion, gc->pCompositeClip); + if (!RegionNotEmpty(®ion)) + return; + goto fallback; + +} + static bool sna_push_pixels_solid_blt(GCPtr gc, PixmapPtr bitmap, @@ -7538,8 +7839,8 @@ static const GCOps sna_gc_ops = { sna_poly_text16, sna_image_text8, sna_image_text16, - NULL, - NULL, + sna_image_glyph, + sna_poly_glyph, sna_push_pixels, };