diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-05-29 17:35:00 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-05-31 14:03:42 +0100 |
commit | 5fff430046db2030f89e49beb66c6476dc3fcd4c (patch) | |
tree | 4bb8c0a526a6a57983428f14f56f6be26322dcda /uxa | |
parent | d31abccd41c417338aac7c681e8bc6bd187b1843 (diff) |
uxa: Mega-Glyphs!
Rewrite glyph rendering to avoid the intermediate buffer, accumulating
the glyph rectangles directly in the backend composite routines. And
modify the glyph cache routines to fully utilise the allocated size of
the tiled buffer on older hardware. To do this we alias all glyph sizes
into the same texture using a technique suggested by Keith Packard.
PineView:
885/856-> 1150/1110 kglyph/s (aa/rgb)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'uxa')
-rw-r--r-- | uxa/uxa-glyphs.c | 1474 | ||||
-rw-r--r-- | uxa/uxa-priv.h | 20 | ||||
-rw-r--r-- | uxa/uxa.c | 43 |
3 files changed, 700 insertions, 837 deletions
diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c index 4a05248c..10d9447c 100644 --- a/uxa/uxa-glyphs.c +++ b/uxa/uxa-glyphs.c @@ -1,11 +1,29 @@ /* - * Copyright © 2008 Red Hat, Inc. + * Copyright © 2010 Intel Corporation + * Partly based on code Copyright © 2008 Red Hat, Inc. * Partly based on code Copyright © 2000 SuSE, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Intel not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the @@ -16,7 +34,7 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -33,11 +51,11 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: Owen Taylor <otaylor@fishsoup.net> - * Based on code by: Keith Packard + * Author: Chris Wilson <chris@chris-wilson.co.uk> + * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net> */ #ifdef HAVE_DIX_CONFIG_H @@ -51,39 +69,19 @@ #include "mipict.h" -#if DEBUG_GLYPH_CACHE -#define DBG_GLYPH_CACHE(a) ErrorF a -#else -#define DBG_GLYPH_CACHE(a) -#endif - /* Width of the pixmaps we use for the caches; this should be less than * max texture size of the driver; this may need to actually come from * the driver. */ -#define CACHE_PICTURE_WIDTH 1024 - -/* Maximum number of glyphs we buffer on the stack before flushing - * rendering to the mask or destination surface. - */ -#define GLYPH_BUFFER_SIZE 256 -#define GLYPH_CACHE_SIZE 256 - -typedef struct { - PicturePtr source; - uxa_composite_rect_t rects[GLYPH_BUFFER_SIZE]; - int count; -} uxa_glyph_buffer_t; - -typedef enum { - UXA_GLYPH_SUCCESS, /* Glyph added to render buffer */ - UXA_GLYPH_FAIL, /* out of memory, etc */ - UXA_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */ -} uxa_glyph_cache_result_t; +#define CACHE_PICTURE_SIZE 1024 +#define GLYPH_MIN_SIZE 8 +#define GLYPH_MAX_SIZE 64 +#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) struct uxa_glyph { uxa_glyph_cache_t *cache; - int pos; + uint16_t x, y; + uint16_t size, pos; }; static int uxa_glyph_index; @@ -98,65 +96,28 @@ static inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv) dixSetPrivate(&glyph->devPrivates, &uxa_glyph_index, priv); } -void uxa_glyphs_init(ScreenPtr pScreen) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - int i = 0; - - dixRequestPrivate(&uxa_glyph_index, 0); /* XXX ignores status */ - - memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); - - uxa_screen->glyphCaches[i].format = PICT_a8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 16; - i++; - uxa_screen->glyphCaches[i].format = PICT_a8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 32; - i++; - uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 16; - i++; - uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8; - uxa_screen->glyphCaches[i].glyphWidth = - uxa_screen->glyphCaches[i].glyphHeight = 32; - i++; - - assert(i == UXA_NUM_GLYPH_CACHES); - - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_screen->glyphCaches[i].columns = - CACHE_PICTURE_WIDTH / uxa_screen->glyphCaches[i].glyphWidth; - } -} +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) -static void uxa_unrealize_glyph_caches(ScreenPtr pScreen, unsigned int format) +static void uxa_unrealize_glyph_caches(ScreenPtr pScreen) { uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); int i; - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) { uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - if (cache->format != format) - continue; - - if (cache->picture) { - FreePicture((pointer) cache->picture, (XID) 0); - cache->picture = NULL; - } + if (cache->picture) + FreePicture(cache->picture, 0); - if (cache->glyphs) { + if (cache->glyphs) xfree(cache->glyphs); - cache->glyphs = NULL; - } - cache->glyphCount = 0; } } -#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) +void uxa_glyphs_fini(ScreenPtr pScreen) +{ + uxa_unrealize_glyph_caches(pScreen); +} /* All caches for a single format share a single pixmap for glyph storage, * allowing mixing glyphs of different sizes without paying a penalty @@ -167,155 +128,148 @@ static void uxa_unrealize_glyph_caches(ScreenPtr pScreen, unsigned int format) * 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, unsigned int format) +static Bool uxa_realize_glyph_caches(ScreenPtr pScreen) { uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - int depth = PIXMAN_FORMAT_DEPTH(format); - PictFormatPtr pPictFormat; - PixmapPtr pPixmap; - PicturePtr pPicture; - CARD32 component_alpha; - int height; + unsigned int formats[] = { + PIXMAN_a8, + PIXMAN_a8r8g8b8, + }; int i; - int error; - pPictFormat = PictureMatchFormat(pScreen, depth, format); - if (!pPictFormat) - return FALSE; - - /* Compute the total vertical size needed for the format */ + memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); - height = 0; - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - int rows; - - if (cache->format != format) - continue; - - cache->yOffset = height; - - rows = (GLYPH_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, - INTEL_CREATE_PIXMAP_TILING_X); - 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; + 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; - ValidatePicture(pPicture); + /* 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; + assert (uxa_pixmap_is_offscreen(pixmap)); - /* And store the picture in all the caches for the format */ + component_alpha = NeedsComponent(pPictFormat->format); + picture = CreatePicture(0, &pixmap->drawable, pPictFormat, + CPComponentAlpha, &component_alpha, + serverClient, &error); - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + pScreen->DestroyPixmap(pixmap); - if (cache->format != format) - continue; + if (!picture) + goto bail; - cache->picture = pPicture; - cache->picture->refcnt++; - cache->glyphs = - xcalloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); - cache->glyphCount = 0; + ValidatePicture(picture); + cache->picture = picture; + cache->glyphs = xcalloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); if (!cache->glyphs) goto bail; - cache->evictionPosition = rand() % GLYPH_CACHE_SIZE; + cache->evict = rand() % GLYPH_CACHE_SIZE; } + assert(i == UXA_NUM_GLYPH_CACHE_FORMATS); - /* Each cache references the picture individually */ - FreePicture((pointer) pPicture, (XID) 0); return TRUE; bail: - uxa_unrealize_glyph_caches(pScreen, format); + uxa_unrealize_glyph_caches(pScreen); return FALSE; } -void uxa_glyphs_fini(ScreenPtr pScreen) + +Bool uxa_glyphs_init(ScreenPtr pScreen) { - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - int i; + if (!dixRequestPrivate(&uxa_glyph_index, 0)) + return FALSE; - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + if (!uxa_realize_glyph_caches(pScreen)) + return FALSE; - if (cache->picture) - uxa_unrealize_glyph_caches(pScreen, cache->format); - } + return TRUE; } -#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) -#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) - /* The most efficient thing to way to upload the glyph to the screen * is to use CopyArea; uxa pixmaps are always offscreen. */ -static Bool -uxa_glyph_cache_upload_glyph(ScreenPtr pScreen, +static void +uxa_glyph_cache_upload_glyph(ScreenPtr screen, uxa_glyph_cache_t * cache, - int pos, GlyphPtr pGlyph) + GlyphPtr glyph, + int x, int y) { - PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; + PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum]; PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable; PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable; PixmapPtr scratch; - GCPtr pGC; + GCPtr gc; - /* UploadToScreen only works if bpp match */ - if (pGlyphPixmap->drawable.bitsPerPixel != - pCachePixmap->drawable.bitsPerPixel) - return FALSE; + gc = GetScratchGC(pCachePixmap->drawable.depth, screen); + if (!gc) + return; - pGC = GetScratchGC(pCachePixmap->drawable.depth, pScreen); - ValidateGC(&pCachePixmap->drawable, pGC); + ValidateGC(&pCachePixmap->drawable, gc); + scratch = pGlyphPixmap; /* Create a temporary bo to stream the updates to the cache */ - scratch = (*pScreen->CreatePixmap)(pScreen, - pGlyph->info.width, - pGlyph->info.height, - pGlyphPixmap->drawable.depth, - UXA_CREATE_PIXMAP_FOR_MAP); - if (scratch) { - (void)uxa_copy_area(&pGlyphPixmap->drawable, - &scratch->drawable, - pGC, - 0, 0, - pGlyph->info.width, pGlyph->info.height, - 0, 0); - } else { - scratch = pGlyphPixmap; + 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; + } } - (void)uxa_copy_area(&scratch->drawable, - &pCachePixmap->drawable, - pGC, - 0, 0, pGlyph->info.width, pGlyph->info.height, - CACHE_X(pos), CACHE_Y(pos)); + uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc, + 0, 0, + glyph->info.width, glyph->info.height, + x, y); if (scratch != pGlyphPixmap) - (*pScreen->DestroyPixmap)(scratch); - - FreeScratchGC(pGC); + screen->DestroyPixmap(scratch); - return TRUE; + FreeScratchGC(gc); } void @@ -334,519 +288,49 @@ uxa_glyph_unrealize(ScreenPtr pScreen, xfree(priv); } -static uxa_glyph_cache_result_t -uxa_glyph_cache_buffer_glyph(ScreenPtr pScreen, - uxa_glyph_cache_t * cache, - uxa_glyph_buffer_t * buffer, - GlyphPtr pGlyph, int xGlyph, int yGlyph) -{ - uxa_composite_rect_t *rect; - struct uxa_glyph *priv = NULL; - int pos; - - if (buffer->source && buffer->source != cache->picture) - return UXA_GLYPH_NEED_FLUSH; - - if (!cache->picture) { - if (!uxa_realize_glyph_caches(pScreen, cache->format)) - return UXA_GLYPH_FAIL; - } - - DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", - cache->glyphWidth, cache->glyphHeight, - cache->format == PICT_a8 ? "A" : "ARGB", - (long)*(CARD32 *) pGlyph->sha1)); - - if (cache->glyphCount < GLYPH_CACHE_SIZE) { - /* Space remaining; we fill from the start */ - pos = cache->glyphCount++; - DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); - } else { - GlyphPtr evicted; - - /* Need to evict an entry. We have to see if any glyphs - * already in the output buffer were at this position in - * the cache - */ - - pos = cache->evictionPosition; - DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); - if (buffer->count) { - int x, y; - int i; - - x = CACHE_X(pos); - y = CACHE_Y(pos); - - for (i = 0; i < buffer->count; i++) { - if (buffer->rects[i].xSrc == x - && buffer->rects[i].ySrc == y) { - DBG_GLYPH_CACHE((" must flush buffer\n")); - return UXA_GLYPH_NEED_FLUSH; - } - } - } - - evicted = cache->glyphs[pos]; - if (evicted != NULL) { - priv = uxa_glyph_get_private(evicted); - uxa_glyph_set_private(evicted, NULL); - } - - /* And pick a new eviction position */ - cache->evictionPosition = rand() % GLYPH_CACHE_SIZE; - } - - /* Now actually upload the glyph into the cache picture; if - * we can't do it with UploadToScreen (because the glyph is - * offscreen, etc), we fall back to CompositePicture. - */ - if (!uxa_glyph_cache_upload_glyph(pScreen, cache, pos, pGlyph)) { - CompositePicture(PictOpSrc, - GlyphPicture(pGlyph)[pScreen->myNum], - None, - cache->picture, - 0, 0, - 0, 0, - CACHE_X(pos), - CACHE_Y(pos), - pGlyph->info.width, - pGlyph->info.height); - } - - if (priv == NULL) { - priv = xalloc(sizeof(struct uxa_glyph)); - if (priv == NULL) { - cache->glyphs[pos] = NULL; - return UXA_GLYPH_FAIL; - } - } - - priv->cache = cache; - priv->pos = pos; - uxa_glyph_set_private(pGlyph, priv); - cache->glyphs[pos] = pGlyph; - - buffer->source = cache->picture; - - rect = &buffer->rects[buffer->count++]; - rect->xSrc = CACHE_X(pos); - rect->ySrc = CACHE_Y(pos); - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; - return UXA_GLYPH_SUCCESS; -} - -static uxa_glyph_cache_result_t -uxa_buffer_glyph(ScreenPtr pScreen, - uxa_glyph_buffer_t * buffer, - GlyphPtr pGlyph, int xGlyph, int yGlyph) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; - int width = pGlyph->info.width; - int height = pGlyph->info.height; - uxa_composite_rect_t *rect; - struct uxa_glyph *priv; - PicturePtr source; - int i; - - if (buffer->count == GLYPH_BUFFER_SIZE) - return UXA_GLYPH_NEED_FLUSH; - - priv = uxa_glyph_get_private(pGlyph); - if (priv != NULL) { - uxa_glyph_cache_t *cache = priv->cache; - int pos = priv->pos; - - if (buffer->source && buffer->source != cache->picture) - return UXA_GLYPH_NEED_FLUSH; - - buffer->source = cache->picture; - - rect = &buffer->rects[buffer->count++]; - rect->xSrc = CACHE_X(pos); - rect->ySrc = CACHE_Y(pos); - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; - return UXA_GLYPH_SUCCESS; - } - - if (PICT_FORMAT_BPP(format) == 1) - format = PICT_a8; - - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - - if (format == cache->format && - width <= cache->glyphWidth && - height <= cache->glyphHeight) { - uxa_glyph_cache_result_t result = - uxa_glyph_cache_buffer_glyph(pScreen, - &uxa_screen-> - glyphCaches[i], - buffer, - pGlyph, xGlyph, - yGlyph); - switch (result) { - case UXA_GLYPH_FAIL: - break; - case UXA_GLYPH_SUCCESS: - case UXA_GLYPH_NEED_FLUSH: - return result; - } - } - } - - /* Couldn't find the glyph in the cache, use the glyph picture directly */ - - source = GlyphPicture(pGlyph)[pScreen->myNum]; - if (buffer->source && buffer->source != source) - return UXA_GLYPH_NEED_FLUSH; - - buffer->source = source; - - rect = &buffer->rects[buffer->count++]; - rect->xSrc = 0; - rect->ySrc = 0; - rect->xDst = xGlyph - pGlyph->info.x; - rect->yDst = yGlyph - pGlyph->info.y; - rect->width = pGlyph->info.width; - rect->height = pGlyph->info.height; - return UXA_GLYPH_SUCCESS; -} - -#undef CACHE_X -#undef CACHE_Y - -static PicturePtr -uxa_glyphs_acquire_source(ScreenPtr screen, - PicturePtr src, - INT16 x, INT16 y, - const uxa_glyph_buffer_t * buffer, - INT16 * out_x, INT16 * out_y) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(screen); - int x1, y1, x2, y2; - int width, height; - int i; - - if (uxa_screen->info->check_composite_texture && - uxa_screen->info->check_composite_texture(screen, src)) { - if (src->pDrawable) { - *out_x = x + src->pDrawable->x; - *out_y = y + src->pDrawable->y; - } else { - *out_x = x; - *out_y = y; - } - return src; - } - - for (i = 0; i < buffer->count; i++) { - const uxa_composite_rect_t *r = &buffer->rects[i]; - - if (r->xDst < x1) - x1 = r->xDst; - if (r->xDst + r->width > x2) - x2 = r->xDst + r->width; - - if (r->yDst < y1) - y1 = r->yDst; - if (r->yDst + r->height > y2) - y2 = r->yDst + r->height; - } - - width = x2 - x1; - height = y2 - y1; - - if (src->pDrawable) { - PicturePtr dst; - - dst = uxa_acquire_drawable(screen, src, - x, y, - width, height, - out_x, out_y); - if (uxa_screen->info->check_composite_texture && - !uxa_screen->info->check_composite_texture(screen, dst)) { - if (dst != src) - FreePicture(dst, 0); - return 0; - } - - return dst; - } - - *out_x = 0; - *out_y = 0; - return uxa_acquire_pattern(screen, src, - PICT_a8r8g8b8, x, y, width, height); -} - -static int -uxa_glyphs_try_driver_composite(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - const uxa_glyph_buffer_t * buffer, - INT16 xSrc, INT16 ySrc, - INT16 xDst, INT16 yDst) -{ - ScreenPtr screen = pDst->pDrawable->pScreen; - uxa_screen_t *uxa_screen = uxa_get_screen(screen); - PicturePtr localSrc; - int src_off_x = 0, src_off_y = 0, mask_off_x, mask_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix = NULL, pMaskPix, pDstPix; - const uxa_composite_rect_t *rects; - int nrect; - - if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, buffer->source, pDst, 0, 0)) { - return -1; - } - - pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); - - pMaskPix = - uxa_get_offscreen_pixmap(buffer->source->pDrawable, &mask_off_x, &mask_off_y); - if(!pMaskPix) - return -1; - - localSrc = uxa_glyphs_acquire_source(screen, pSrc, - xSrc, ySrc, - buffer, - &xSrc, &ySrc); - if (!localSrc) - return 0; - - if (localSrc->pDrawable) { - pSrcPix = - uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) { - if (localSrc != pSrc) - FreePicture(localSrc, 0); - return 0; - } - - xSrc += localSrc->pDrawable->x; - ySrc += localSrc->pDrawable->y; - } - - if (!(*uxa_screen->info->prepare_composite) - (op, localSrc, buffer->source, pDst, pSrcPix, pMaskPix, pDstPix)) { - if (localSrc != pSrc) - FreePicture(localSrc, 0); - return -1; - } - - nrect = buffer->count; - rects = buffer->rects; - do { - INT16 _xDst = rects->xDst + pDst->pDrawable->x; - INT16 _yDst = rects->yDst + pDst->pDrawable->y; - INT16 _xMask = rects->xSrc + buffer->source->pDrawable->x; - INT16 _yMask = rects->ySrc + buffer->source->pDrawable->y; - INT16 _xSrc = xSrc, _ySrc = ySrc; - - RegionRec region; - BoxPtr pbox; - int nbox; - - if (!miComputeCompositeRegion(®ion, - localSrc, buffer->source, pDst, - _xSrc, _ySrc, - _xMask, _yMask, - _xDst, _yDst, - rects->width, rects->height)) - goto next_rect; - - _xSrc += src_off_x - _xDst; - _ySrc += src_off_y - _yDst; - _xMask += mask_off_x - _xDst; - _yMask += mask_off_y - _yDst; - - nbox = REGION_NUM_RECTS(®ion); - pbox = REGION_RECTS(®ion); - while (nbox--) { - (*uxa_screen->info->composite) (pDstPix, - pbox->x1 + _xSrc, - pbox->y1 + _ySrc, - pbox->x1 + _xMask, - pbox->y1 + _yMask, - pbox->x1 + dst_off_x, - pbox->y1 + dst_off_y, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - -next_rect: - REGION_UNINIT(screen, ®ion); - - rects++; - } while (--nrect); - (*uxa_screen->info->done_composite) (pDstPix); - - if (localSrc != pSrc) - FreePicture(localSrc, 0); - - return 1; -} - -static void -uxa_glyphs_to_dst(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - const uxa_glyph_buffer_t * buffer, - INT16 xSrc, INT16 ySrc, - INT16 xDst, INT16 yDst) -{ - if (uxa_glyphs_try_driver_composite(op, pSrc, pDst, buffer, - xSrc, ySrc, - xDst, yDst) != 1) { - int i; - - for (i = 0; i < buffer->count; i++) { - const uxa_composite_rect_t *rect = &buffer->rects[i]; - - CompositePicture(op, - pSrc, buffer->source, pDst, - xSrc + rect->xDst - xDst, - ySrc + rect->yDst - yDst, - rect->xSrc, rect->ySrc, - rect->xDst, rect->yDst, - rect->width, rect->height); - } - } -} - -static int -uxa_glyphs_try_driver_add_to_mask(PicturePtr pDst, - const uxa_glyph_buffer_t *buffer) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); - int src_off_x, src_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pDstPix; - const uxa_composite_rect_t *rects; - int nrect; - - if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (PictOpAdd, buffer->source, NULL, pDst, 0, 0)) { - return -1; - } - - pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); - dst_off_x += pDst->pDrawable->x; - dst_off_y += pDst->pDrawable->y; - - pSrcPix = - uxa_get_offscreen_pixmap(buffer->source->pDrawable, &src_off_x, &src_off_y); - if(!pSrcPix) - return -1; - src_off_x += buffer->source->pDrawable->x; - src_off_y += buffer->source->pDrawable->y; - - if (!(*uxa_screen->info->prepare_composite) - (PictOpAdd, buffer->source, NULL, pDst, pSrcPix, NULL, pDstPix)) - return -1; - - rects = buffer->rects; - nrect = buffer->count; - do { - INT16 xDst = rects->xDst + dst_off_x; - INT16 yDst = rects->yDst + dst_off_y; - INT16 xSrc = rects->xSrc + src_off_x; - INT16 ySrc = rects->ySrc + src_off_y; - - /* We trust the device clipping on the target and the - * specialised construction of the glyph mask and source - * so that we can skip computing the clipped composite - * region (miComputeCompositeRects). - */ - - (*uxa_screen->info->composite) (pDstPix, - xSrc, ySrc, - 0, 0, - xDst, yDst, - rects->width, - rects->height); - - rects++; - } while (--nrect); - (*uxa_screen->info->done_composite) (pDstPix); - - return 1; -} - -static void uxa_glyphs_to_mask(PicturePtr pDst, const uxa_glyph_buffer_t *buffer) -{ - if (uxa_glyphs_try_driver_add_to_mask(pDst, buffer) != 1) { - int i; - - for (i = 0; i < buffer->count; i++) { - const uxa_composite_rect_t *r = &buffer->rects[i]; - - uxa_check_composite(PictOpAdd, buffer->source, NULL, pDst, - r->xSrc, r->ySrc, - 0, 0, - r->xDst, r->yDst, - r->width, r->height); - } - } -} - /* Cut and paste from render/glyph.c - probably should export it instead */ static void uxa_glyph_extents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents) { int x1, x2, y1, y2; - int n; - GlyphPtr glyph; - int x, y; + int x, y, n; - x = 0; - y = 0; - extents->x1 = MAXSHORT; - extents->x2 = MINSHORT; - extents->y1 = MAXSHORT; - extents->y2 = MINSHORT; + x1 = y1 = MAXSHORT; + x2 = y2 = MINSHORT; + x = y = 0; while (nlist--) { x += list->xOff; y += list->yOff; n = list->len; list++; while (n--) { - glyph = *glyphs++; - x1 = x - glyph->info.x; - if (x1 < MINSHORT) - x1 = MINSHORT; - y1 = y - glyph->info.y; - if (y1 < MINSHORT) - y1 = MINSHORT; - x2 = x1 + glyph->info.width; - if (x2 > MAXSHORT) - x2 = MAXSHORT; - y2 = y1 + glyph->info.height; - if (y2 > MAXSHORT) - y2 = MAXSHORT; - if (x1 < extents->x1) - extents->x1 = x1; - if (x2 > extents->x2) - extents->x2 = x2; - if (y1 < extents->y1) - extents->y1 = y1; - if (y2 > extents->y2) - extents->y2 = y2; + GlyphPtr glyph = *glyphs++; + int v; + + v = x - glyph->info.x; + if (v < x1) + x1 = v; + v += glyph->info.width; + if (v > x2) + x2 = v; + + v = y - glyph->info.y; + if (v < y1) + y1 = v; + v += glyph->info.height; + if (v > y2) + y2 = v; + x += glyph->info.xOff; y += glyph->info.yOff; } } + + extents->x1 = x1 < MINSHORT ? MINSHORT : x1; + extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; + extents->y1 = y1 < MINSHORT ? MINSHORT : y1; + extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; } /** @@ -858,7 +342,6 @@ uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) { int x1, x2, y1, y2; int n; - GlyphPtr glyph; int x, y; BoxRec extents; Bool first = TRUE; @@ -875,7 +358,7 @@ uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) n = list->len; list++; while (n--) { - glyph = *glyphs++; + GlyphPtr glyph = *glyphs++; if (glyph->info.width == 0 || glyph->info.height == 0) { x += glyph->info.xOff; @@ -981,6 +464,7 @@ uxa_check_glyphs(CARD8 op, pixman_image_unref(image); return; } + ValidatePicture(mask); x = -extents.x1; y = -extents.y1; @@ -1039,6 +523,491 @@ uxa_check_glyphs(CARD8 op, } } +static inline unsigned int +uxa_glyph_size_to_count(int size) +{ + size /= GLYPH_MIN_SIZE; + return size * size; +} + +static inline unsigned int +uxa_glyph_count_to_mask(int count) +{ + return ~(count - 1); +} + +static inline unsigned int +uxa_glyph_size_to_mask(int size) +{ + return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size)); +} + +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 = GlyphPicture(glyph)[screen->myNum]; + 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) + xfree(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 = xalloc(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 int +uxa_glyphs_to_dst(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + INT16 src_x, INT16 src_y, + INT16 xDst, INT16 yDst, + int nlist, GlyphListPtr list, GlyphPtr * glyphs, + BoxPtr extents) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PixmapPtr src_pixmap, dst_pixmap; + PicturePtr localSrc, glyph_atlas; + int x, y, n, nrect; + BoxRec box; + + if (uxa_screen->info->check_composite_texture && + uxa_screen->info->check_composite_texture(screen, pSrc)) { + if (pSrc->pDrawable) { + int src_off_x, src_off_y; + + src_pixmap = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); + if (src_pixmap == NULL) + return -1; + + src_x += pSrc->pDrawable->x + src_off_x; + src_y += pSrc->pDrawable->y + src_off_y; + } else { + src_pixmap = NULL; + } + localSrc = pSrc; + } else { + int width, height; + + if (extents == NULL) { + uxa_glyph_extents(nlist, list, glyphs, &box); + extents = &box; + } + + width = extents->x2 - extents->x1; + height = extents->y2 - extents->y1; + if (width == 0 || height == 0) + return 0; + + if (pSrc->pDrawable) { + int src_off_x, src_off_y; + + src_off_x = extents->x1 - xDst; + src_off_y = extents->y1 - yDst; + localSrc = uxa_acquire_drawable(screen, pSrc, + src_x + src_off_x, src_y + src_off_y, + width, height, + &src_x, &src_y); + if (uxa_screen->info->check_composite_texture && + !uxa_screen->info->check_composite_texture(screen, localSrc)) { + if (localSrc != pSrc) + FreePicture(localSrc, 0); + return -1; + } + + src_pixmap = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); + if (src_pixmap == NULL) { + if (localSrc != pSrc) + FreePicture(localSrc, 0); + return -1; + } + + src_x += localSrc->pDrawable->x + src_off_x; + src_y += localSrc->pDrawable->y + src_off_y; + } else { + localSrc = uxa_acquire_pattern(screen, pSrc, + PICT_a8r8g8b8, x, y, width, height); + if (!localSrc) + return 1; + + src_pixmap = uxa_get_drawable_pixmap(localSrc->pDrawable); + if (src_pixmap == NULL) { + FreePicture(localSrc, 0); + return -1; + } + + src_x = src_y = 0; + } + } + + dst_pixmap = uxa_get_offscreen_pixmap(pDst->pDrawable, &x, &y); + x += xDst + pDst->pDrawable->x - list->xOff; + y += yDst + pDst->pDrawable->y - list->yOff; + + glyph_atlas = NULL; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + GlyphPtr glyph = *glyphs++; + PicturePtr this_atlas; + int mask_x, mask_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) { + mask_x = priv->x; + mask_y = priv->y; + this_atlas = priv->cache->picture; + } else { + if (glyph_atlas) { + uxa_screen->info->done_composite(dst_pixmap); + glyph_atlas = NULL; + } + this_atlas = uxa_glyph_cache(screen, glyph, &mask_x, &mask_y); + if (this_atlas == NULL) { + /* no cache for this glyph */ + this_atlas = GlyphPicture(glyph)[screen->myNum]; + mask_x = mask_y = 0; + } + } + + if (this_atlas != glyph_atlas) { + PixmapPtr mask_pixmap; + + if (glyph_atlas) + uxa_screen->info->done_composite(dst_pixmap); + + mask_pixmap = + uxa_get_drawable_pixmap(this_atlas->pDrawable); + assert (uxa_pixmap_is_offscreen(mask_pixmap)); + + if (!uxa_screen->info->prepare_composite(op, + localSrc, this_atlas, pDst, + src_pixmap, mask_pixmap, dst_pixmap)) + return -1; + + glyph_atlas = this_atlas; + } + + nrect = REGION_NUM_RECTS(pDst->pCompositeClip); + if (nrect == 1) { + uxa_screen->info->composite(dst_pixmap, + x + src_x, y + src_y, + mask_x, mask_y, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } else { + BoxPtr rects = REGION_RECTS(pDst->pCompositeClip); + do { + int x1 = x - glyph->info.x, dx = 0; + int y1 = y - glyph->info.y, dy = 0; + int x2 = x1 + glyph->info.width; + int y2 = y1 + glyph->info.height; + + if (x1 < rects->x1) + dx = rects->x1 - x1, x1 = rects->x1; + if (x2 > rects->x2) + x2 = rects->x2; + if (y1 < rects->y1) + dy = rects->y1 - y1, y1 = rects->y1; + if (y2 > rects->y2) + y2 = rects->y2; + + if (x1 < x2 && y1 < y2) { + uxa_screen->info->composite(dst_pixmap, + x1 + src_x, y1 + src_y, + dx + mask_x, dy + mask_y, + x1, y1, + x2 - x1, y2 - y1); + } + rects++; + } while (--nrect); + } + +next_glyph: + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + if (glyph_atlas) + uxa_screen->info->done_composite(dst_pixmap); + + if (localSrc != pSrc) + FreePicture(localSrc, 0); + + return 0; +} + +static void +uxa_clear_pixmap(ScreenPtr screen, + uxa_screen_t *uxa_screen, + PixmapPtr pixmap) +{ + if (uxa_screen->info->check_solid && + !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES)) + goto fallback; + + if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0)) + goto fallback; + + uxa_screen->info->solid(pixmap, + 0, 0, + pixmap->drawable.width, + pixmap->drawable.height); + + uxa_screen->info->done_solid(pixmap); + return; + +fallback: + { + GCPtr gc; + + gc = GetScratchGC(pixmap->drawable.depth, screen); + if (gc) { + xRectangle rect; + + ValidateGC(&pixmap->drawable, gc); + + rect.x = 0; + rect.y = 0; + rect.width = pixmap->drawable.width; + rect.height = pixmap->drawable.height; + gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); + + FreeScratchGC(gc); + } + } +} + +static int +uxa_glyphs_via_mask(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + INT16 xDst, INT16 yDst, + int nlist, GlyphListPtr list, GlyphPtr * glyphs, + BoxPtr extents) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + CARD32 component_alpha; + PixmapPtr pixmap; + PicturePtr glyph_atlas, mask; + int x, y, width, height; + int dst_off_x, dst_off_y; + int n, error; + BoxRec box; + + if (!extents) { + uxa_glyph_extents(nlist, list, glyphs, &box); + + if (box.x2 <= box.x1 || box.y2 <= box.y1) + return 0; + + extents = &box; + dst_off_x = box.x1; + dst_off_y = box.y1; + } else { + dst_off_x = dst_off_y = 0; + } + + width = extents->x2 - extents->x1; + height = extents->y2 - extents->y1; + x = -extents->x1; + y = -extents->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; + + 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) + 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 src_x, src_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) { + src_x = priv->x; + src_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, &src_x, &src_y); + if (this_atlas == NULL) { + /* no cache for this glyph */ + this_atlas = GlyphPicture(glyph)[screen->myNum]; + src_x = src_y = 0; + } + } + + if (this_atlas != glyph_atlas) { + PixmapPtr src_pixmap; + + if (glyph_atlas) + uxa_screen->info->done_composite(pixmap); + + src_pixmap = + uxa_get_drawable_pixmap(this_atlas->pDrawable); + assert (uxa_pixmap_is_offscreen(src_pixmap)); + + if (!uxa_screen->info->prepare_composite(PictOpAdd, + this_atlas, NULL, mask, + src_pixmap, NULL, pixmap)) + return -1; + + glyph_atlas = this_atlas; + } + + uxa_screen->info->composite(pixmap, + src_x, src_y, + 0, 0, + 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(mask, 0); + return 0; +} + void uxa_glyphs(CARD8 op, PicturePtr pSrc, @@ -1049,17 +1018,10 @@ uxa_glyphs(CARD8 op, { ScreenPtr screen = pDst->pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(screen); - PicturePtr pMask = NULL; - 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 }; Bool have_extents = FALSE; - CARD32 component_alpha; - uxa_glyph_buffer_t buffer; + int width, height, ret; PicturePtr localDst = pDst; if (!uxa_screen->info->prepare_composite || @@ -1071,6 +1033,12 @@ fallback: 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); @@ -1098,13 +1066,12 @@ fallback: } } - x = y = 0; if (!maskFormat && uxa_screen->info->check_composite_target && !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { int depth = pDst->pDrawable->depth; PixmapPtr pixmap; - int error; + int x, y, error; GCPtr gc; pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); @@ -1166,118 +1133,25 @@ fallback: } if (maskFormat) { - PixmapPtr pixmap; - GCPtr gc; - xRectangle rect; - - if (!have_extents) { - 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; - x = -extents.x1; - y = -extents.y1; - have_extents = TRUE; - } - - if (maskFormat->depth == 1) { - PictFormatPtr a8Format = - PictureMatchFormat(screen, 8, PICT_a8); - - if (a8Format) - maskFormat = a8Format; - } - - pixmap = screen->CreatePixmap(screen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pixmap) { - if (localDst != pDst) - FreePicture(localDst, 0); - return; - } - - gc = GetScratchGC(pixmap->drawable.depth, screen); - ValidateGC(&pixmap->drawable, gc); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); - FreeScratchGC(gc); - - component_alpha = NeedsComponent(maskFormat->format); - pMask = CreatePicture(0, &pixmap->drawable, - maskFormat, CPComponentAlpha, - &component_alpha, serverClient, &error); - screen->DestroyPixmap(pixmap); - - if (!pMask) { - if (localDst != pDst) - FreePicture(localDst, 0); - return; - } - - ValidatePicture(pMask); - } - - buffer.count = 0; - buffer.source = 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 && - uxa_buffer_glyph(screen, &buffer, glyph, x, - y) == UXA_GLYPH_NEED_FLUSH) { - if (maskFormat) - uxa_glyphs_to_mask(pMask, &buffer); - else - uxa_glyphs_to_dst(op, pSrc, localDst, - &buffer, xSrc, ySrc, - xDst, yDst); - - buffer.count = 0; - buffer.source = NULL; - - uxa_buffer_glyph(screen, &buffer, glyph, x, y); - } - - x += glyph->info.xOff; - y += glyph->info.yOff; - } - list++; - } - - if (buffer.count) { - if (maskFormat) - uxa_glyphs_to_mask(pMask, &buffer); - else - uxa_glyphs_to_dst(op, pSrc, localDst, &buffer, - xSrc, ySrc, xDst, yDst); + ret = uxa_glyphs_via_mask(op, + pSrc, localDst, maskFormat, + xSrc, ySrc, + xDst, yDst, + nlist, list, glyphs, + have_extents ? &extents : NULL); + } else { + ret = uxa_glyphs_to_dst(op, + pSrc, localDst, + xSrc, ySrc, + xDst, yDst, + nlist, list, glyphs, + have_extents ? &extents : NULL); } + if (ret) { + if (localDst != pDst) + FreePicture(localDst, 0); - if (maskFormat) { - if (localDst == pDst) { - x = extents.x1; - y = extents.y1; - } else - x = y = 0; - CompositePicture(op, - pSrc, - pMask, - localDst, - xSrc + x - xDst, - ySrc + y - yDst, - 0, 0, - x, y, - width, height); - FreePicture(pMask, 0); + goto fallback; } if (localDst != pDst) { diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h index 47e0b6a9..36625de8 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -103,21 +103,13 @@ char uxa_drawable_location(DrawablePtr pDrawable); #endif typedef struct { - /* The identity of the cache, statically configured at initialization */ - unsigned int format; - int glyphWidth; - int glyphHeight; - - GlyphPtr *glyphs; - int glyphCount; /* Current number of glyphs */ - PicturePtr picture; /* Where the glyphs of the cache are stored */ - int yOffset; /* y location within the picture where the cache starts */ - int columns; /* Number of columns the glyphs are layed out in */ - int evictionPosition; /* Next random position to evict a glyph */ + GlyphPtr *glyphs; + uint16_t count; + uint16_t evict; } uxa_glyph_cache_t; -#define UXA_NUM_GLYPH_CACHES 4 +#define UXA_NUM_GLYPH_CACHE_FORMATS 2 typedef struct { uint32_t color; @@ -154,7 +146,7 @@ typedef struct { unsigned disableFbCount; unsigned offScreenCounter; - uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHES]; + uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHE_FORMATS]; PicturePtr solid_clear, solid_black, solid_white; uxa_solid_cache_t solid_cache[UXA_NUM_SOLID_CACHE]; @@ -445,7 +437,7 @@ uxa_get_rgba_from_pixel(CARD32 pixel, CARD32 format); /* uxa_glyph.c */ -void uxa_glyphs_init(ScreenPtr pScreen); +Bool uxa_glyphs_init(ScreenPtr pScreen); void uxa_glyphs_fini(ScreenPtr pScreen); @@ -432,9 +432,6 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) { uxa_screen_t *uxa_screen; ScrnInfoPtr scrn = xf86Screens[screen->myNum]; -#ifdef RENDER - PictureScreenPtr ps; -#endif if (!uxa_driver) return FALSE; @@ -463,10 +460,6 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) "non-NULL\n", screen->myNum); return FALSE; } -#ifdef RENDER - ps = GetPictureScreenIfSet(screen); -#endif - uxa_screen = xcalloc(sizeof(uxa_screen_t), 1); if (!uxa_screen) { @@ -516,27 +509,30 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) scrn->EnableDisableFBAccess = uxa_xorg_enable_disable_fb_access; #ifdef RENDER - if (ps) { - uxa_screen->SavedComposite = ps->Composite; - ps->Composite = uxa_composite; + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + uxa_screen->SavedComposite = ps->Composite; + ps->Composite = uxa_composite; - uxa_screen->SavedCompositeRects = ps->CompositeRects; - ps->CompositeRects = uxa_solid_rects; + uxa_screen->SavedCompositeRects = ps->CompositeRects; + ps->CompositeRects = uxa_solid_rects; - uxa_screen->SavedGlyphs = ps->Glyphs; - ps->Glyphs = uxa_glyphs; + uxa_screen->SavedGlyphs = ps->Glyphs; + ps->Glyphs = uxa_glyphs; - uxa_screen->SavedUnrealizeGlyph = ps->UnrealizeGlyph; - ps->UnrealizeGlyph = uxa_glyph_unrealize; + uxa_screen->SavedUnrealizeGlyph = ps->UnrealizeGlyph; + ps->UnrealizeGlyph = uxa_glyph_unrealize; - uxa_screen->SavedTriangles = ps->Triangles; - ps->Triangles = uxa_triangles; + uxa_screen->SavedTriangles = ps->Triangles; + ps->Triangles = uxa_triangles; - uxa_screen->SavedTrapezoids = ps->Trapezoids; - ps->Trapezoids = uxa_trapezoids; + uxa_screen->SavedTrapezoids = ps->Trapezoids; + ps->Trapezoids = uxa_trapezoids; - uxa_screen->SavedAddTraps = ps->AddTraps; - ps->AddTraps = uxa_check_add_traps; + uxa_screen->SavedAddTraps = ps->AddTraps; + ps->AddTraps = uxa_check_add_traps; + } } #endif @@ -548,7 +544,8 @@ Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) ShmRegisterFuncs(screen, &uxa_shm_funcs); #endif - uxa_glyphs_init(screen); + if (!uxa_glyphs_init(screen)) + return FALSE; LogMessage(X_INFO, "UXA(%d): Driver registered support for the following" |