static int
uxa_glyphs_to_dst(CARD8 op,
		  PicturePtr pSrc,
		  PicturePtr pDst,
		  INT16 xSrc, INT16 ySrc,
		  int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
	ScreenPtr screen = pDst->pDrawable->pScreen;
	int x, y, n;

	xSrc -= list->xOff;
	ySrc -= list->yOff;
	x = y = 0;
	while (nlist--) {
		x += list->xOff;
		y += list->yOff;
		n = list->len;
		while (n--) {
			GlyphPtr glyph = *glyphs++;
			PicturePtr glyph_atlas;
			int glyph_x, glyph_y;
			struct uxa_glyph *priv;

			if (glyph->info.width == 0 || glyph->info.height == 0)
				goto next_glyph;

			priv = uxa_glyph_get_private(glyph);
			if (priv != NULL) {
				glyph_x = priv->x;
				glyph_y = priv->y;
				glyph_atlas = priv->cache->picture;
			} else {
				glyph_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
				if (glyph_atlas == NULL) {
					/* no cache for this glyph */
					glyph_atlas = GetGlyphPicture(glyph, screen);
					glyph_x = glyph_y = 0;
				}
			}

			uxa_composite(op,
				      pSrc, glyph_atlas, pDst,
				      xSrc + x - glyph->info.x,
				      ySrc + y - glyph->info.y,
				      glyph_x, glyph_y,
				      x - glyph->info.x,
				      y - glyph->info.y,
				      glyph->info.width, glyph->info.height);

next_glyph:
			x += glyph->info.xOff;
			y += glyph->info.yOff;
		}
		list++;
	}

	return 0;
}
Пример #2
0
static ExaGlyphCacheResult
exaBufferGlyph(ScreenPtr pScreen,
               ExaGlyphBufferPtr buffer,
               GlyphPtr pGlyph,
               PicturePtr pSrc,
               PicturePtr pDst,
               INT16 xSrc,
               INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
{
    ExaScreenPriv(pScreen);
    unsigned int format = (GetGlyphPicture(pGlyph, pScreen))->format;
    int width = pGlyph->info.width;
    int height = pGlyph->info.height;
    ExaCompositeRectPtr rect;
    PicturePtr mask;
    int i;

    if (buffer->count == GLYPH_BUFFER_SIZE)
        return ExaGlyphNeedFlush;

    if (PICT_FORMAT_BPP(format) == 1)
        format = PICT_a8;

    for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
        ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];

        if (format == cache->format &&
            width <= cache->glyphWidth && height <= cache->glyphHeight) {
            ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
                                                                  &pExaScr->
                                                                  glyphCaches
                                                                  [i],
                                                                  buffer,
                                                                  pGlyph,
                                                                  pSrc,
                                                                  pDst,
                                                                  xSrc, ySrc,
                                                                  xMask, yMask,
                                                                  xDst, yDst);

            switch (result) {
            case ExaGlyphFail:
                break;
            case ExaGlyphSuccess:
            case ExaGlyphNeedFlush:
                return result;
            }
        }
    }

    /* Couldn't find the glyph in the cache, use the glyph picture directly */

    mask = GetGlyphPicture(pGlyph, pScreen);
    if (buffer->mask && buffer->mask != mask)
        return ExaGlyphNeedFlush;

    buffer->mask = mask;

    rect = &buffer->rects[buffer->count];
    rect->xSrc = xSrc;
    rect->ySrc = ySrc;
    rect->xMask = xMask;
    rect->yMask = yMask;
    rect->xDst = xDst;
    rect->yDst = yDst;
    rect->width = width;
    rect->height = height;

    buffer->count++;

    return ExaGlyphSuccess;
}
Пример #3
0
/* The most efficient thing to way to upload the glyph to the screen
 * is to use the UploadToScreen() driver hook; this allows us to
 * pipeline glyph uploads and to avoid creating gpu backed pixmaps for
 * glyphs that we'll never use again.
 *
 * If we can't do it with UploadToScreen (because the glyph has a gpu copy,
 * etc), we fall back to CompositePicture.
 *
 * We need to damage the cache pixmap manually in either case because the damage
 * layer unwrapped the picture screen before calling exaGlyphs.
 */
static void
exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
                         ExaGlyphCachePtr cache, int x, int y, GlyphPtr pGlyph)
{
    ExaScreenPriv(pScreen);
    PicturePtr pGlyphPicture = GetGlyphPicture(pGlyph, pScreen);
    PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;

    ExaPixmapPriv(pGlyphPixmap);
    PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;

    if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut ||
        pExaPixmap->accel_blocked)
        goto composite;

    /* If the glyph pixmap is already uploaded, no point in doing
     * things this way */
    if (exaPixmapHasGpuCopy(pGlyphPixmap))
        goto composite;

    /* UploadToScreen only works if bpp match */
    if (pGlyphPixmap->drawable.bitsPerPixel !=
        pCachePixmap->drawable.bitsPerPixel)
        goto composite;

    if (pExaScr->do_migration) {
        ExaMigrationRec pixmaps[1];

        /* cache pixmap must have a gpu copy. */
        pixmaps[0].as_dst = TRUE;
        pixmaps[0].as_src = FALSE;
        pixmaps[0].pPix = pCachePixmap;
        pixmaps[0].pReg = NULL;
        exaDoMigration(pixmaps, 1, TRUE);
    }

    if (!exaPixmapHasGpuCopy(pCachePixmap))
        goto composite;

    /* x,y are in pixmap coordinates, no need for cache{X,Y}off */
    if (pExaScr->info->UploadToScreen(pCachePixmap,
                                      x,
                                      y,
                                      pGlyph->info.width,
                                      pGlyph->info.height,
                                      (char *) pExaPixmap->sys_ptr,
                                      pExaPixmap->sys_pitch))
        goto damage;

 composite:
    CompositePicture(PictOpSrc,
                     pGlyphPicture,
                     None,
                     cache->picture,
                     0, 0, 0, 0, x, y, pGlyph->info.width, pGlyph->info.height);

 damage:
    /* The cache pixmap isn't a window, so no need to offset coordinates. */
    exaPixmapDirty(pCachePixmap,
                   x, y, x + cache->glyphWidth, y + cache->glyphHeight);
}
Пример #4
0
void
fbGlyphs(CARD8 op,
	 PicturePtr pSrc,
	 PicturePtr pDst,
	 PictFormatPtr maskFormat,
	 INT16 xSrc,
	 INT16 ySrc, int nlist,
	 GlyphListPtr list,
	 GlyphPtr *glyphs)
{
#define N_STACK_GLYPHS 512
    ScreenPtr pScreen = pDst->pDrawable->pScreen;
    pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
    pixman_glyph_t *pglyphs = stack_glyphs;
    pixman_image_t *srcImage, *dstImage;
    int srcXoff, srcYoff, dstXoff, dstYoff;
    GlyphPtr glyph;
    int n_glyphs;
    int x, y;
    int i, n;
    int xDst = list->xOff, yDst = list->yOff;

    miCompositeSourceValidate(pSrc);

    n_glyphs = 0;
    for (i = 0; i < nlist; ++i)
	n_glyphs += list[i].len;

    if (!glyphCache)
	glyphCache = pixman_glyph_cache_create();

    pixman_glyph_cache_freeze (glyphCache);

    if (n_glyphs > N_STACK_GLYPHS) {
	if (!(pglyphs = malloc (n_glyphs * sizeof (pixman_glyph_t))))
	    goto out;
    }

    i = 0;
    x = y = 0;
    while (nlist--) {
        x += list->xOff;
        y += list->yOff;
        n = list->len;
        while (n--) {
	    const void *g;

            glyph = *glyphs++;

	    if (!(g = pixman_glyph_cache_lookup (glyphCache, glyph, NULL))) {
		pixman_image_t *glyphImage;
		PicturePtr pPicture;
		int xoff, yoff;

		pPicture = GetGlyphPicture(glyph, pScreen);
		if (!pPicture) {
		    n_glyphs--;
		    goto next;
		}

		if (!(glyphImage = image_from_pict(pPicture, FALSE, &xoff, &yoff)))
		    goto out;

		g = pixman_glyph_cache_insert(glyphCache, glyph, NULL,
					      glyph->info.x,
					      glyph->info.y,
					      glyphImage);

		free_pixman_pict(pPicture, glyphImage);

		if (!g)
		    goto out;
	    }

	    pglyphs[i].x = x;
	    pglyphs[i].y = y;
	    pglyphs[i].glyph = g;
	    i++;

	next:
            x += glyph->info.xOff;
            y += glyph->info.yOff;
	}
	list++;
    }

    if (!(srcImage = image_from_pict(pSrc, FALSE, &srcXoff, &srcYoff)))
	goto out;

    if (!(dstImage = image_from_pict(pDst, TRUE, &dstXoff, &dstYoff)))
	goto out_free_src;

    if (maskFormat) {
	pixman_format_code_t format;
	pixman_box32_t extents;

	format = maskFormat->format | (maskFormat->depth << 24);

	pixman_glyph_get_extents(glyphCache, n_glyphs, pglyphs, &extents);

	pixman_composite_glyphs(op, srcImage, dstImage, format,
				xSrc + srcXoff + extents.x1 - xDst, ySrc + srcYoff + extents.y1 - yDst,
				extents.x1, extents.y1,
				extents.x1 + dstXoff, extents.y1 + dstYoff,
				extents.x2 - extents.x1,
				extents.y2 - extents.y1,
				glyphCache, n_glyphs, pglyphs);
    }
    else {
	pixman_composite_glyphs_no_mask(op, srcImage, dstImage,
					xSrc + srcXoff - xDst, ySrc + srcYoff - yDst,
					dstXoff, dstYoff,
					glyphCache, n_glyphs, pglyphs);
    }

    free_pixman_pict(pDst, dstImage);

out_free_src:
    free_pixman_pict(pSrc, srcImage);

out:
    pixman_glyph_cache_thaw(glyphCache);
    if (pglyphs != stack_glyphs)
	free(pglyphs);
}
static int
uxa_glyphs_via_mask(CARD8 op,
		    PicturePtr pSrc,
		    PicturePtr pDst,
		    PictFormatPtr maskFormat,
		    INT16 xSrc, INT16 ySrc,
		    int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
	ScreenPtr screen = pDst->pDrawable->pScreen;
	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
	CARD32 component_alpha;
	PixmapPtr pixmap, white_pixmap;
	PicturePtr glyph_atlas, mask, white;
	int xDst = list->xOff, yDst = list->yOff;
	int x, y, width, height;
	int dst_off_x, dst_off_y;
	int n, error;
	BoxRec box;

	uxa_glyph_extents(nlist, list, glyphs, &box);
	if (box.x2 <= box.x1 || box.y2 <= box.y1)
		return 0;

	dst_off_x = box.x1;
	dst_off_y = box.y1;

	width  = box.x2 - box.x1;
	height = box.y2 - box.y1;
	x = -box.x1;
	y = -box.y1;

	if (maskFormat->depth == 1) {
		PictFormatPtr a8Format =
			PictureMatchFormat(screen, 8, PICT_a8);

		if (!a8Format)
			return -1;

		maskFormat = a8Format;
	}

	pixmap = screen->CreatePixmap(screen, width, height,
				      maskFormat->depth,
				      CREATE_PIXMAP_USAGE_SCRATCH);
	if (!pixmap)
		return 1;

	if (!uxa_pixmap_is_offscreen(pixmap)) {
		screen->DestroyPixmap(pixmap);
		return -1;
	}

	white_pixmap = NULL;
	white = create_white_solid(screen);
	if (white)
		white_pixmap = uxa_get_drawable_pixmap(white->pDrawable);
	if (!white_pixmap) {
		if (white)
			FreePicture(white, 0);
		screen->DestroyPixmap(pixmap);
		return -1;
	}

	uxa_clear_pixmap(screen, uxa_screen, pixmap);

	component_alpha = NeedsComponent(maskFormat->format);
	mask = CreatePicture(0, &pixmap->drawable,
			      maskFormat, CPComponentAlpha,
			      &component_alpha, serverClient, &error);
	screen->DestroyPixmap(pixmap);

	if (!mask) {
		FreePicture(white, 0);
		return 1;
	}

	ValidatePicture(mask);

	glyph_atlas = NULL;
	while (nlist--) {
		x += list->xOff;
		y += list->yOff;
		n = list->len;
		while (n--) {
			GlyphPtr glyph = *glyphs++;
			PicturePtr this_atlas;
			int glyph_x, glyph_y;
			struct uxa_glyph *priv;

			if (glyph->info.width == 0 || glyph->info.height == 0)
				goto next_glyph;

			priv = uxa_glyph_get_private(glyph);
			if (priv != NULL) {
				glyph_x = priv->x;
				glyph_y = priv->y;
				this_atlas = priv->cache->picture;
			} else {
				if (glyph_atlas) {
					uxa_screen->info->done_composite(pixmap);
					glyph_atlas = NULL;
				}
				this_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
				if (this_atlas == NULL) {
					/* no cache for this glyph */
					this_atlas = GetGlyphPicture(glyph, screen);
					glyph_x = glyph_y = 0;
				}
			}

			if (this_atlas != glyph_atlas) {
				PixmapPtr glyph_pixmap;

				if (glyph_atlas)
					uxa_screen->info->done_composite(pixmap);

				glyph_pixmap =
					uxa_get_drawable_pixmap(this_atlas->pDrawable);
				if (!uxa_pixmap_is_offscreen(glyph_pixmap) ||
				    !uxa_screen->info->prepare_composite(PictOpAdd,
									 white, this_atlas, mask,
									 white_pixmap, glyph_pixmap, pixmap)) {
					FreePicture(white, 0);
					FreePicture(mask, 0);
					return -1;
				}

				glyph_atlas = this_atlas;
			}

			uxa_screen->info->composite(pixmap,
						    0, 0,
						    glyph_x, glyph_y,
						    x - glyph->info.x,
						    y - glyph->info.y,
						    glyph->info.width,
						    glyph->info.height);

next_glyph:
			x += glyph->info.xOff;
			y += glyph->info.yOff;
		}
		list++;
	}
	if (glyph_atlas)
		uxa_screen->info->done_composite(pixmap);

	uxa_composite(op,
		      pSrc, mask, pDst,
		      dst_off_x + xSrc - xDst,
		      dst_off_y + ySrc - yDst,
		      0, 0,
		      dst_off_x, dst_off_y,
		      width, height);

	FreePicture(white, 0);
	FreePicture(mask, 0);
	return 0;
}
static PicturePtr
uxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y)
{
	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
	PicturePtr glyph_picture = GetGlyphPicture(glyph, screen);
	uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
	struct uxa_glyph *priv = NULL;
	int size, mask, pos, s;

	if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE)
		return NULL;

	for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
		if (glyph->info.width <= size && glyph->info.height <= size)
			break;

	s = uxa_glyph_size_to_count(size);
	mask = uxa_glyph_count_to_mask(s);
	pos = (cache->count + s - 1) & mask;
	if (pos < GLYPH_CACHE_SIZE) {
		cache->count = pos + s;
	} else {
		for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
			int i = cache->evict & uxa_glyph_size_to_mask(s);
			GlyphPtr evicted = cache->glyphs[i];
			if (evicted == NULL)
				continue;

			priv = uxa_glyph_get_private(evicted);
			if (priv->size >= s) {
				cache->glyphs[i] = NULL;
				uxa_glyph_set_private(evicted, NULL);
				pos = cache->evict & uxa_glyph_size_to_mask(size);
			} else
				priv = NULL;
			break;
		}
		if (priv == NULL) {
			int count = uxa_glyph_size_to_count(size);
			mask = uxa_glyph_count_to_mask(count);
			pos = cache->evict & mask;
			for (s = 0; s < count; s++) {
				GlyphPtr evicted = cache->glyphs[pos + s];
				if (evicted != NULL) {
					if (priv != NULL)
						free(priv);

					priv = uxa_glyph_get_private(evicted);
					uxa_glyph_set_private(evicted, NULL);
					cache->glyphs[pos + s] = NULL;
				}
			}
		}

		/* And pick a new eviction position */
		cache->evict = rand() % GLYPH_CACHE_SIZE;
	}

	if (priv == NULL) {
		priv = malloc(sizeof(struct uxa_glyph));
		if (priv == NULL)
			return NULL;
	}

	uxa_glyph_set_private(glyph, priv);
	cache->glyphs[pos] = glyph;

	priv->cache = cache;
	priv->size = size;
	priv->pos = pos;
	s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
	priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
	priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
	for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
		if (pos & 1)
			priv->x += s;
		if (pos & 2)
			priv->y += s;
		pos >>= 2;
	}

	uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);

	*out_x = priv->x;
	*out_y = priv->y;
	return cache->picture;
}
static void
uxa_check_glyphs(CARD8 op,
		 PicturePtr src,
		 PicturePtr dst,
		 PictFormatPtr maskFormat,
		 INT16 xSrc,
		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
	pixman_image_t *image;
	PixmapPtr scratch;
	PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL;
	int width = 0, height = 0;
	int x, y, n;
	int xDst = list->xOff, yDst = list->yOff;
	BoxRec extents = { 0, 0, 0, 0 };
	CARD8 mask_op = 0;

	if (maskFormat) {
		pixman_format_code_t format;
		CARD32 component_alpha;
		xRenderColor color;
		int error;

		uxa_glyph_extents(nlist, list, glyphs, &extents);
		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
			return;

		width = extents.x2 - extents.x1;
		height = extents.y2 - extents.y1;

		format = maskFormat->format |
			(BitsPerPixel(maskFormat->depth) << 24);
		image =
			pixman_image_create_bits(format, width, height, NULL, 0);
		if (!image)
			return;

		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
						 PIXMAN_FORMAT_DEPTH(format),
						 PIXMAN_FORMAT_BPP(format),
						 pixman_image_get_stride(image),
						 pixman_image_get_data(image));

		if (!scratch) {
			pixman_image_unref(image);
			return;
		}

		component_alpha = NeedsComponent(maskFormat->format);
		mask = CreatePicture(0, &scratch->drawable,
				     maskFormat, CPComponentAlpha,
				     &component_alpha, serverClient, &error);
		if (!mask) {
			FreeScratchPixmapHeader(scratch);
			pixman_image_unref(image);
			return;
		}
		ValidatePicture(mask);

		x = -extents.x1;
		y = -extents.y1;

		color.red = color.green = color.blue = color.alpha = 0xffff;
		white = CreateSolidPicture(0, &color, &error);

		mask_op = op;
		op = PictOpAdd;

		mask_src = src;
		src = white;

		mask_dst = dst;
		dst = mask;
	} else {
		mask = dst;
		x = 0;
		y = 0;
	}

	while (nlist--) {
		x += list->xOff;
		y += list->yOff;
		n = list->len;
		while (n--) {
			GlyphPtr glyph = *glyphs++;
			PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen);
			if (g) {
				CompositePicture(op, src, g, dst,
						 xSrc + (x - glyph->info.x) - xDst,
						 ySrc + (y - glyph->info.y) - yDst,
						 0, 0,
						 x - glyph->info.x,
						 y - glyph->info.y,
						 glyph->info.width,
						 glyph->info.height);
			}

			x += glyph->info.xOff;
			y += glyph->info.yOff;
		}
		list++;
	}

	if (white)
		FreePicture(white, 0);

	if (maskFormat) {
		x = extents.x1;
		y = extents.y1;
		CompositePicture(mask_op, mask_src, mask, mask_dst,
				 xSrc + x - xDst,
				 ySrc + y - yDst,
				 0, 0,
				 x, y,
				 width, height);
		FreePicture(mask, 0);
		FreeScratchPixmapHeader(scratch);
		pixman_image_unref(image);
	}
}
/* The most efficient thing to way to upload the glyph to the screen
 * is to use CopyArea; uxa pixmaps are always offscreen.
 */
static void
uxa_glyph_cache_upload_glyph(ScreenPtr screen,
			     uxa_glyph_cache_t * cache,
			     GlyphPtr glyph,
			     int x, int y)
{
	PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen);
	PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
	PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
	PixmapPtr scratch;
	GCPtr gc;

	gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
	if (!gc)
		return;

	ValidateGC(&pCachePixmap->drawable, gc);

	scratch = pGlyphPixmap;
	/* Create a temporary bo to stream the updates to the cache */
	if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
	    !uxa_pixmap_is_offscreen(scratch)) {
		scratch = screen->CreatePixmap(screen,
					       glyph->info.width,
					       glyph->info.height,
					       pCachePixmap->drawable.depth,
					       UXA_CREATE_PIXMAP_FOR_MAP);
		if (scratch) {
			if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
				PicturePtr picture;
				int error;

				picture = CreatePicture(0, &scratch->drawable,
							PictureMatchFormat(screen,
									   pCachePixmap->drawable.depth,
									   cache->picture->format),
							0, NULL,
							serverClient, &error);
				if (picture) {
					ValidatePicture(picture);
					uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture,
						      0, 0,
						      0, 0,
						      0, 0,
						      glyph->info.width, glyph->info.height);
					FreePicture(picture, 0);
				}
			} else {
				uxa_copy_area(&pGlyphPixmap->drawable,
					      &scratch->drawable,
					      gc,
					      0, 0,
					      glyph->info.width, glyph->info.height,
					      0, 0);
			}
		} else {
			scratch = pGlyphPixmap;
		}
	}

	uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc,
		      0, 0,
		      glyph->info.width, glyph->info.height,
		      x, y);

	if (scratch != pGlyphPixmap)
		screen->DestroyPixmap(scratch);

	FreeScratchGC(gc);
}