/* All caches for a single format share a single pixmap for glyph storage, * allowing mixing glyphs of different sizes without paying a penalty * for switching between mask pixmaps. (Note that for a size of font * right at the border between two sizes, we might be switching for almost * every glyph.) * * This function allocates the storage pixmap, and then fills in the * rest of the allocated structures for all caches with the given format. */ static Bool exaRealizeGlyphCaches(ScreenPtr pScreen, unsigned int format) { ExaScreenPriv(pScreen); int depth = PIXMAN_FORMAT_DEPTH(format); PictFormatPtr pPictFormat; PixmapPtr pPixmap; PicturePtr pPicture; CARD32 component_alpha; int height; int i; int error; pPictFormat = PictureMatchFormat(pScreen, depth, format); if (!pPictFormat) return FALSE; /* Compute the total vertical size needed for the format */ height = 0; for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; int rows; if (cache->format != format) continue; cache->yOffset = height; rows = (cache->size + cache->columns - 1) / cache->columns; height += rows * cache->glyphHeight; } /* Now allocate the pixmap and picture */ pPixmap = (*pScreen->CreatePixmap) (pScreen, CACHE_PICTURE_WIDTH, height, depth, 0); if (!pPixmap) return FALSE; component_alpha = NeedsComponent(pPictFormat->format); pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, CPComponentAlpha, &component_alpha, serverClient, &error); (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ if (!pPicture) return FALSE; /* And store the picture in all the caches for the format */ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; int j; if (cache->format != format) continue; cache->picture = pPicture; cache->picture->refcnt++; cache->hashEntries = malloc(sizeof(int) * cache->hashSize); cache->glyphs = malloc(sizeof(ExaCachedGlyphRec) * cache->size); cache->glyphCount = 0; if (!cache->hashEntries || !cache->glyphs) goto bail; for (j = 0; j < cache->hashSize; j++) cache->hashEntries[j] = -1; cache->evictionPosition = rand() % cache->size; } /* Each cache references the picture individually */ FreePicture((pointer) pPicture, (XID) 0); return TRUE; bail: exaUnrealizeGlyphCaches(pScreen, format); return FALSE; }
void exaGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) { PixmapPtr pMaskPixmap = 0; PicturePtr pMask = NULL; ScreenPtr pScreen = pDst->pDrawable->pScreen; int width = 0, height = 0; int x, y; int first_xOff = list->xOff, first_yOff = list->yOff; int n; GlyphPtr glyph; int error; BoxRec extents = { 0, 0, 0, 0 }; CARD32 component_alpha; ExaGlyphBuffer buffer; if (maskFormat) { ExaScreenPriv(pScreen); GCPtr pGC; xRectangle rect; GlyphExtents(nlist, list, glyphs, &extents); if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) return; width = extents.x2 - extents.x1; height = extents.y2 - extents.y1; if (maskFormat->depth == 1) { PictFormatPtr a8Format = PictureMatchFormat(pScreen, 8, PICT_a8); if (a8Format) maskFormat = a8Format; } pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, maskFormat->depth, CREATE_PIXMAP_USAGE_SCRATCH); if (!pMaskPixmap) return; component_alpha = NeedsComponent(maskFormat->format); pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, CPComponentAlpha, &component_alpha, serverClient, &error); if (!pMask || (!component_alpha && pExaScr->info->CheckComposite && !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask))) { PictFormatPtr argbFormat; (*pScreen->DestroyPixmap) (pMaskPixmap); if (!pMask) return; /* The driver can't seem to composite to a8, let's try argb (but * without component-alpha) */ FreePicture((pointer) pMask, (XID) 0); argbFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8); if (argbFormat) maskFormat = argbFormat; pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, maskFormat->depth, CREATE_PIXMAP_USAGE_SCRATCH); if (!pMaskPixmap) return; pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, 0, 0, serverClient, &error); if (!pMask) { (*pScreen->DestroyPixmap) (pMaskPixmap); return; } } pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen); ValidateGC(&pMaskPixmap->drawable, pGC); rect.x = 0; rect.y = 0; rect.width = width; rect.height = height; (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); FreeScratchGC(pGC); x = -extents.x1; y = -extents.y1; } else { x = 0; y = 0; } buffer.count = 0; buffer.mask = NULL; while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; while (n--) { glyph = *glyphs++; if (glyph->info.width > 0 && glyph->info.height > 0) { /* pGlyph->info.{x,y} compensate for empty space in the glyph. */ if (maskFormat) { if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) { exaGlyphsToMask(pMask, &buffer); exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask, 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y); } } else { if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush) { exaGlyphsToDst(pSrc, pDst, &buffer); exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst, xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff, 0, 0, x - glyph->info.x, y - glyph->info.y); } } } x += glyph->info.xOff; y += glyph->info.yOff; } list++; } if (buffer.count) { if (maskFormat) exaGlyphsToMask(pMask, &buffer); else exaGlyphsToDst(pSrc, pDst, &buffer); } if (maskFormat) { x = extents.x1; y = extents.y1; CompositePicture(op, pSrc, pMask, pDst, xSrc + x - first_xOff, ySrc + y - first_yOff, 0, 0, x, y, width, height); FreePicture((pointer) pMask, (XID) 0); (*pScreen->DestroyPixmap) (pMaskPixmap); } }
void uxa_glyphs(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); if (uxa_screen->info->flags & UXA_USE_GLAMOR) { int ok; uxa_picture_prepare_access(pDst, UXA_GLAMOR_ACCESS_RW); uxa_picture_prepare_access(pSrc, UXA_GLAMOR_ACCESS_RO); ok = glamor_glyphs_nf(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); uxa_picture_finish_access(pSrc, UXA_GLAMOR_ACCESS_RO); uxa_picture_finish_access(pDst, UXA_GLAMOR_ACCESS_RW); if (!ok) goto fallback; return; } if (!uxa_screen->info->prepare_composite || uxa_screen->force_fallback || !uxa_drawable_is_offscreen(pDst->pDrawable) || pDst->alphaMap || pSrc->alphaMap || /* XXX we fail to handle (rare) non-solid sources correctly. */ !is_solid(pSrc)) { fallback: uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); return; } /* basic sanity check */ if (uxa_screen->info->check_composite && !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) { goto fallback; } ValidatePicture(pSrc); ValidatePicture(pDst); if (!maskFormat) { /* If we don't have a mask format but all the glyphs have the same format, * require ComponentAlpha and don't intersect, use the glyph format as mask * format for the full benefits of the glyph cache. */ if (NeedsComponent(list[0].format->format)) { Bool sameFormat = TRUE; int i; maskFormat = list[0].format; for (i = 0; i < nlist; i++) { if (maskFormat->format != list[i].format->format) { sameFormat = FALSE; break; } } if (!sameFormat || uxa_glyphs_intersect(nlist, list, glyphs)) maskFormat = NULL; } } if (!maskFormat) { if (uxa_glyphs_to_dst(op, pSrc, pDst, xSrc, ySrc, nlist, list, glyphs)) goto fallback; } else { if (uxa_glyphs_via_mask(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs)) goto fallback; } }
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 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); } }
/* All caches for a single format share a single pixmap for glyph storage, * allowing mixing glyphs of different sizes without paying a penalty * for switching between source pixmaps. (Note that for a size of font * right at the border between two sizes, we might be switching for almost * every glyph.) * * This function allocates the storage pixmap, and then fills in the * rest of the allocated structures for all caches with the given format. */ static Bool uxa_realize_glyph_caches(ScreenPtr pScreen) { uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); unsigned int formats[] = { PIXMAN_a8, PIXMAN_a8r8g8b8, }; int i; if (uxa_screen->glyph_cache_initialized) return TRUE; uxa_screen->glyph_cache_initialized = TRUE; memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; PixmapPtr pixmap; PicturePtr picture; CARD32 component_alpha; int depth = PIXMAN_FORMAT_DEPTH(formats[i]); int error; PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]); if (!pPictFormat) goto bail; /* Now allocate the pixmap and picture */ pixmap = pScreen->CreatePixmap(pScreen, CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth, INTEL_CREATE_PIXMAP_TILING_X); if (!pixmap) goto bail; if (!uxa_pixmap_is_offscreen(pixmap)) { /* Presume shadow is in-effect */ pScreen->DestroyPixmap(pixmap); uxa_unrealize_glyph_caches(pScreen); return TRUE; } component_alpha = NeedsComponent(pPictFormat->format); picture = CreatePicture(0, &pixmap->drawable, pPictFormat, CPComponentAlpha, &component_alpha, serverClient, &error); pScreen->DestroyPixmap(pixmap); if (!picture) goto bail; ValidatePicture(picture); cache->picture = picture; cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); if (!cache->glyphs) goto bail; cache->evict = rand() % GLYPH_CACHE_SIZE; } assert(i == UXA_NUM_GLYPH_CACHE_FORMATS); return TRUE; bail: uxa_unrealize_glyph_caches(pScreen); return FALSE; }
void miGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) { PicturePtr pPicture; PixmapPtr pMaskPixmap = 0; PicturePtr pMask; ScreenPtr pScreen = pDst->pDrawable->pScreen; int width = 0, height = 0; int x, y; int xDst = list->xOff, yDst = list->yOff; int n; GlyphPtr glyph; int error; BoxRec extents = { 0, 0, 0, 0 }; CARD32 component_alpha; if (maskFormat) { GCPtr pGC; xRectangle rect; GlyphExtents(nlist, list, glyphs, &extents); if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) return; width = extents.x2 - extents.x1; height = extents.y2 - extents.y1; pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, maskFormat->depth, CREATE_PIXMAP_USAGE_SCRATCH); if (!pMaskPixmap) return; component_alpha = NeedsComponent(maskFormat->format); pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, CPComponentAlpha, &component_alpha, serverClient, &error); if (!pMask) { (*pScreen->DestroyPixmap) (pMaskPixmap); return; } pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen); ValidateGC(&pMaskPixmap->drawable, pGC); rect.x = 0; rect.y = 0; rect.width = width; rect.height = height; (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); FreeScratchGC(pGC); x = -extents.x1; y = -extents.y1; } else { pMask = pDst; x = 0; y = 0; } while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; while (n--) { glyph = *glyphs++; pPicture = GlyphPicture(glyph)[pScreen->myNum]; if (pPicture) { if (maskFormat) { CompositePicture(PictOpAdd, pPicture, None, pMask, 0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y, glyph->info.width, glyph->info.height); } else { CompositePicture(op, pSrc, pPicture, pDst, 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 (maskFormat) { x = extents.x1; y = extents.y1; CompositePicture(op, pSrc, pMask, pDst, xSrc + x - xDst, ySrc + y - yDst, 0, 0, x, y, width, height); FreePicture((pointer) pMask, (XID) 0); (*pScreen->DestroyPixmap) (pMaskPixmap); } }