diff --git a/src/i830_uxa.c b/src/i830_uxa.c index 208de07e..eb21fb56 100644 --- a/src/i830_uxa.c +++ b/src/i830_uxa.c @@ -936,6 +936,7 @@ i830_uxa_create_pixmap(ScreenPtr screen, int w, int h, int depth, if (depth == 1) return fbCreatePixmap(screen, w, h, depth, usage); + if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32) return fbCreatePixmap(screen, w, h, depth, usage); @@ -1134,6 +1135,9 @@ Bool i830_uxa_init(ScreenPtr screen) intel->uxa_driver->finish_access = i830_uxa_finish_access; intel->uxa_driver->pixmap_is_offscreen = i830_uxa_pixmap_is_offscreen; + screen->CreatePixmap = i830_uxa_create_pixmap; + screen->DestroyPixmap = i830_uxa_destroy_pixmap; + if (!uxa_driver_init(screen, intel->uxa_driver)) { xf86DrvMsg(scrn->scrnIndex, X_ERROR, "UXA initialization failed\n"); @@ -1141,9 +1145,6 @@ Bool i830_uxa_init(ScreenPtr screen) return FALSE; } - screen->CreatePixmap = i830_uxa_create_pixmap; - screen->DestroyPixmap = i830_uxa_destroy_pixmap; - uxa_set_fallback_debug(screen, intel->fallback_debug); return TRUE; 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 - * Based on code by: Keith Packard + * Author: Chris Wilson + * Based on code by: Keith Packard and Owen Taylor */ #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; +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 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; - } -} - -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(cache->picture, 0); - if (cache->picture) { - FreePicture((pointer) cache->picture, (XID) 0); - cache->picture = NULL; - } - - 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; + memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); - /* Compute the total vertical size needed for the format */ - - 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; + 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; - if (cache->format != format) - continue; + /* 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)); - cache->yOffset = height; + component_alpha = NeedsComponent(pPictFormat->format); + picture = CreatePicture(0, &pixmap->drawable, pPictFormat, + CPComponentAlpha, &component_alpha, + serverClient, &error); - rows = (GLYPH_CACHE_SIZE + cache->columns - 1) / cache->columns; - height += rows * cache->glyphHeight; - } + pScreen->DestroyPixmap(pixmap); - /* Now allocate the pixmap and picture */ + if (!picture) + goto bail; - 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; - - ValidatePicture(pPicture); - - /* And store the picture in all the caches for the format */ - - for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { - uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; - - if (cache->format != format) - continue; - - 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); + screen->DestroyPixmap(scratch); - FreeScratchGC(pGC); - - 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); + 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); - 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); - } - - 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); diff --git a/uxa/uxa.c b/uxa/uxa.c index ce03fa07..330b3893 100644 --- a/uxa/uxa.c +++ b/uxa/uxa.c @@ -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"