xf86-video-intel: src/sna/sna_accel.c src/sna/sna_glyphs.c src/sna/sna.h

Chris Wilson ickle at kemper.freedesktop.org
Mon Sep 10 05:57:55 PDT 2012


 src/sna/sna.h        |    6 +
 src/sna/sna_accel.c  |    2 
 src/sna/sna_glyphs.c |  305 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 313 insertions(+)

New commits:
commit b0d14071f7b60729c223af925935227393fbd3ee
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Sep 10 13:53:45 2012 +0100

    sna: Workaround issue with global glyph privates and shared ZaphodHeads
    
    Under ZaphodHeads we end up with multple screens accessing the common
    sna_glyph_key and so cause conflicting updates and erroneous references
    into the screen-local texture atlases.
    
    Two approaches can be tried here. Transition to a screen-specific
    private key introduced with xorg-1.13, or to move the glyph cache (and
    the rest of the gpu state tracker) down into the device private rather
    than screen private. This is neither of those, but a workaround to avoid
    reusing the incorrect entries from shared screens.
    
    Reported-by: Stephen Liang <inteldriver at angrywalls.com>
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54707
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 44e7f6e..382c0a5 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -709,6 +709,12 @@ void sna_glyphs(CARD8 op,
 		int nlist,
 		GlyphListPtr list,
 		GlyphPtr *glyphs);
+void sna_glyphs__shared(CARD8 op,
+			PicturePtr src,
+			PicturePtr dst,
+			PictFormatPtr mask,
+			INT16 src_x, INT16 src_y,
+			int nlist, GlyphListPtr list, GlyphPtr *glyphs);
 void sna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph);
 void sna_glyphs_close(struct sna *sna);
 
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 7574847..4ef9019 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -14357,6 +14357,8 @@ static bool sna_picture_init(ScreenPtr screen)
 	ps->Composite = sna_composite;
 	ps->CompositeRects = sna_composite_rectangles;
 	ps->Glyphs = sna_glyphs;
+	if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0]))
+		ps->Glyphs = sna_glyphs__shared;
 	ps->UnrealizeGlyph = sna_glyph_unrealize;
 	ps->AddTraps = sna_add_traps;
 	ps->Trapezoids = sna_composite_trapezoids;
diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
index 7a96fab..53494e3 100644
--- a/src/sna/sna_glyphs.c
+++ b/src/sna/sna_glyphs.c
@@ -194,6 +194,9 @@ bool sna_glyphs_create(struct sna *sna)
 	if (!can_render(sna))
 		return true;
 
+	if (xf86IsEntityShared(sna->scrn->entityList[0]))
+		return true;
+
 	for (i = 0; i < ARRAY_SIZE(formats); i++) {
 		struct sna_glyph_cache *cache = &sna->render.glyph[i];
 		struct sna_pixmap *priv;
@@ -409,6 +412,9 @@ glyph_cache(ScreenPtr screen,
 	assert(cache->glyphs[pos] == NULL);
 
 	priv = sna_glyph(glyph);
+	DBG(("%s(%d): adding glyph to cache %d, pos %d\n",
+	     __FUNCTION__, screen->myNum,
+	     PICT_FORMAT_RGB(glyph_picture->format) != 0, pos));
 	cache->glyphs[pos] = priv;
 	priv->atlas = cache->picture;
 	priv->size = size;
@@ -1694,11 +1700,308 @@ fallback:
 	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
 }
 
+static bool
+glyphs_via_image(struct sna *sna,
+		 CARD8 op,
+		 PicturePtr src,
+		 PicturePtr dst,
+		 PictFormatPtr format,
+		 INT16 src_x, INT16 src_y,
+		 int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+	ScreenPtr screen = dst->pDrawable->pScreen;
+	CARD32 component_alpha;
+	PixmapPtr pixmap;
+	PicturePtr mask;
+	int16_t x, y, width, height;
+	pixman_image_t *mask_image;
+	int error;
+	BoxRec box;
+
+	if (NO_GLYPHS_VIA_MASK)
+		return false;
+
+	DBG(("%s(op=%d, src=(%d, %d), nlist=%d,  dst=(%d, %d)+(%d, %d))\n",
+	     __FUNCTION__, op, src_x, src_y, nlist,
+	     list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y));
+
+	glyph_extents(nlist, list, glyphs, &box);
+	if (box.x2 <= box.x1 || box.y2 <= box.y1)
+		return true;
+
+	DBG(("%s: bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
+	     box.x1, box.y1, box.x2, box.y2));
+
+	if (!sna_compute_composite_extents(&box,
+					   src, NULL, dst,
+					   src_x, src_y,
+					   0, 0,
+					   box.x1, box.y1,
+					   box.x2 - box.x1,
+					   box.y2 - box.y1))
+		return true;
+
+	DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
+	     box.x1, box.y1, box.x2, box.y2));
+
+	width  = box.x2 - box.x1;
+	height = box.y2 - box.y1;
+	box.x1 -= dst->pDrawable->x;
+	box.y1 -= dst->pDrawable->y;
+	x = -box.x1;
+	y = -box.y1;
+	src_x += box.x1 - list->xOff;
+	src_y += box.y1 - list->yOff;
+
+	if (format->depth < 8) {
+		format = PictureMatchFormat(screen, 8, PICT_a8);
+		if (!format)
+			return false;
+	}
+
+	DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
+	     __FUNCTION__, (unsigned long)format->format,
+	     format->depth, (uint32_t)width*height*format->depth));
+
+	pixmap = sna_pixmap_create_upload(screen,
+					  width, height,
+					  format->depth,
+					  KGEM_BUFFER_WRITE);
+	if (!pixmap)
+		return false;
+
+	mask_image =
+		pixman_image_create_bits(format->depth << 24 | format->format,
+					 width, height,
+					 pixmap->devPrivate.ptr,
+					 pixmap->devKind);
+	if (mask_image == NULL)
+		goto err_pixmap;
+
+	memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
+#if HAS_PIXMAN_GLYPHS
+	if (sna->render.glyph_cache) {
+		pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
+		pixman_glyph_t *pglyphs = stack_glyphs;
+		pixman_glyph_cache_t *cache;
+		int count, n;
+
+		cache = sna->render.glyph_cache;
+		pixman_glyph_cache_freeze(cache);
+
+		count = 0;
+		for (n = 0; n < nlist; ++n)
+			count += list[n].len;
+		if (count > N_STACK_GLYPHS) {
+			pglyphs = malloc (count * sizeof(pixman_glyph_t));
+			if (pglyphs == NULL)
+				goto err_pixmap;
+		}
+
+		count = 0;
+		do {
+			n = list->len;
+			x += list->xOff;
+			y += list->yOff;
+			while (n--) {
+				GlyphPtr g = *glyphs++;
+				const void *ptr;
+
+				if (g->info.width == 0 || g->info.height == 0)
+					goto next_pglyph;
+
+				ptr = pixman_glyph_cache_lookup(cache, g, NULL);
+				if (ptr == NULL) {
+					pixman_image_t *glyph_image;
+
+					glyph_image = sna_glyph_get_image(g, screen);
+					if (glyph_image == NULL)
+						goto next_pglyph;
+
+					ptr = pixman_glyph_cache_insert(cache, g, NULL,
+									g->info.x,
+									g->info.y,
+									glyph_image);
+					if (ptr == NULL)
+						goto next_pglyph;
+				}
+
+				pglyphs[count].x = x;
+				pglyphs[count].y = y;
+				pglyphs[count].glyph = ptr;
+				count++;
+
+next_pglyph:
+				x += g->info.xOff;
+				y += g->info.yOff;
+			}
+			list++;
+		} while (--nlist);
+
+		pixman_composite_glyphs_no_mask(PIXMAN_OP_ADD,
+						sna->render.white_image,
+						mask_image,
+						0, 0,
+						0, 0,
+						cache, count, pglyphs);
+		pixman_glyph_cache_thaw(cache);
+		if (pglyphs != stack_glyphs)
+			free(pglyphs);
+	} else
+#endif
+		do {
+			int n = list->len;
+			x += list->xOff;
+			y += list->yOff;
+			while (n--) {
+				GlyphPtr g = *glyphs++;
+				pixman_image_t *glyph_image;
+				int16_t xi, yi;
+
+				if (g->info.width == 0 || g->info.height == 0)
+					goto next_image;
+
+				/* If the mask has been cropped, it is likely
+				 * that some of the glyphs fall outside.
+				 */
+				xi = x - g->info.x;
+				yi = y - g->info.y;
+				if (xi >= width || yi >= height)
+					goto next_image;
+				if (xi + g->info.width  <= 0 ||
+				    yi + g->info.height <= 0)
+					goto next_image;
+
+				glyph_image =
+					sna_glyph_get_image(g, dst->pDrawable->pScreen);
+
+				DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
+				     __FUNCTION__,
+				     xi, yi,
+				     g->info.width,
+				     g->info.height));
+
+				if (list->format == format) {
+					assert(pixman_image_get_format(glyph_image) == pixman_image_get_format(mask_image));
+					pixman_image_composite(PictOpAdd,
+							       glyph_image,
+							       NULL,
+							       mask_image,
+							       0, 0,
+							       0, 0,
+							       xi, yi,
+							       g->info.width,
+							       g->info.height);
+				} else {
+					pixman_image_composite(PictOpAdd,
+							       sna->render.white_image,
+							       glyph_image,
+							       mask_image,
+							       0, 0,
+							       0, 0,
+							       xi, yi,
+							       g->info.width,
+							       g->info.height);
+				}
+
+next_image:
+				x += g->info.xOff;
+				y += g->info.yOff;
+			}
+			list++;
+		} while (--nlist);
+	pixman_image_unref(mask_image);
+
+	component_alpha = NeedsComponent(format->format);
+
+	mask = CreatePicture(0, &pixmap->drawable,
+			     format, CPComponentAlpha,
+			     &component_alpha, serverClient, &error);
+	if (!mask)
+		goto err_pixmap;
+
+	ValidatePicture(mask);
+
+	sna_composite(op,
+		      src, mask, dst,
+		      src_x, src_y,
+		      0, 0,
+		      box.x1, box.y1,
+		      width, height);
+	FreePicture(mask, 0);
+err_pixmap:
+	sna_pixmap_destroy(pixmap);
+	return TRUE;
+}
+
+void
+sna_glyphs__shared(CARD8 op,
+		   PicturePtr src,
+		   PicturePtr dst,
+		   PictFormatPtr mask,
+		   INT16 src_x, INT16 src_y,
+		   int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
+	struct sna *sna = to_sna_from_pixmap(pixmap);
+	struct sna_pixmap *priv;
+
+	DBG(("%s(op=%d, nlist=%d, src=(%d, %d))\n",
+	     __FUNCTION__, op, nlist, src_x, src_y));
+
+	if (REGION_NUM_RECTS(dst->pCompositeClip) == 0)
+		return;
+
+	if (FALLBACK)
+		goto fallback;
+
+	if (!can_render(sna)) {
+		DBG(("%s: wedged\n", __FUNCTION__));
+		goto fallback;
+	}
+
+	if (dst->alphaMap) {
+		DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__));
+		goto fallback;
+	}
+
+	priv = sna_pixmap(pixmap);
+	if (priv == NULL) {
+		DBG(("%s: fallback -- destination unattached\n", __FUNCTION__));
+		goto fallback;
+	}
+
+	if ((too_small(priv) || DAMAGE_IS_ALL(priv->cpu_damage)) &&
+	    !picture_is_gpu(src)) {
+		DBG(("%s: fallback -- too small (%dx%d)\n",
+		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height));
+		goto fallback;
+	}
+
+	if (!mask) {
+		mask = glyphs_format(nlist, list, glyphs);
+		DBG(("%s: substituting mask? %d\n", __FUNCTION__, mask!=NULL));
+	}
+	if (mask) {
+		if (glyphs_via_image(sna, op,
+				     src, dst, mask,
+				     src_x, src_y,
+				     nlist, list, glyphs))
+			return;
+	}
+
+fallback:
+	glyphs_fallback(op, src, dst, mask, src_x, src_y, nlist, list, glyphs);
+}
+
 void
 sna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
 {
 	struct sna_glyph *priv = sna_glyph(glyph);
 
+	DBG(("%s: screen=%d, glyph(image?=%d, atlas?=%d)\n",
+	     __FUNCTION__, screen->myNum, !!priv->image, !!priv->atlas));
+
 	if (priv->image) {
 #if HAS_PIXMAN_GLYPHS
 		struct sna *sna = to_sna_from_screen(screen);
@@ -1713,6 +2016,8 @@ sna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
 	if (priv->atlas) {
 		struct sna *sna = to_sna_from_screen(screen);
 		struct sna_glyph_cache *cache = &sna->render.glyph[priv->pos&1];
+		DBG(("%s: releasing glyph pos %d from cache %d\n",
+		     __FUNCTION__, priv->pos >> 1, priv->pos & 1));
 		assert(cache->glyphs[priv->pos >> 1] == priv);
 		cache->glyphs[priv->pos >> 1] = NULL;
 		priv->atlas = NULL;


More information about the xorg-commit mailing list