summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-07-14 13:05:27 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-07-14 14:15:11 +0100
commit95fdd9af5c8a8360d02debc400e75869c36f05ca (patch)
treef2aba50030905a690983f22b89ae17c4644c1126
parent3f764ee4c50567cfb831495d42cb6c2bb94055ad (diff)
sna: Enable pixman_glyphs if available
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--configure.ac4
-rw-r--r--src/sna/sna_glyphs.c387
-rw-r--r--src/sna/sna_render.h3
3 files changed, 328 insertions, 66 deletions
diff --git a/configure.ac b/configure.ac
index d323da7f..8cbbbc13 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,6 +118,10 @@ AC_ARG_ENABLE(kms-only, AS_HELP_STRING([--enable-kms-only],
required_xorg_xserver_version=1.6
required_pixman_version=0.24
+if pkg-config --exists 'pixman-1 >= 0.27.1'; then
+ AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])
+fi
+
AC_ARG_ENABLE(sna,
AS_HELP_STRING([--enable-sna],
[Enable SandyBridge's New Acceleration (SNA) [default=auto]]),
diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
index 6f9faf47..8c4796a3 100644
--- a/src/sna/sna_glyphs.c
+++ b/src/sna/sna_glyphs.c
@@ -81,6 +81,8 @@
#define GLYPH_MAX_SIZE 64
#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
+#define N_STACK_GLYPHS 512
+
#if HAS_DEBUG_FULL
static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function)
{
@@ -146,6 +148,12 @@ void sna_glyphs_close(struct sna *sna)
FreePicture(render->white_picture, 0);
render->white_picture = NULL;
}
+#if HAS_PIXMAN_GLYPHS
+ if (render->glyph_cache) {
+ pixman_glyph_cache_destroy(render->glyph_cache);
+ render->glyph_cache = NULL;
+ }
+#endif
}
/* All caches for a single format share a single pixmap for glyph storage,
@@ -170,8 +178,18 @@ bool sna_glyphs_create(struct sna *sna)
DBG(("%s\n", __FUNCTION__));
+#if HAS_PIXMAN_GLYPHS
+ sna->render.glyph_cache = pixman_glyph_cache_create();
+ if (sna->render.glyph_cache == NULL)
+ goto bail;
+#endif
+
+ sna->render.white_image = pixman_image_create_solid_fill(&white);
+ if (sna->render.white_image == NULL)
+ goto bail;
+
if (sna->kgem.wedged || !sna->have_render)
- return TRUE;
+ return true;
for (i = 0; i < ARRAY_SIZE(formats); i++) {
struct sna_glyph_cache *cache = &sna->render.glyph[i];
@@ -222,14 +240,16 @@ bool sna_glyphs_create(struct sna *sna)
cache->evict = rand() % GLYPH_CACHE_SIZE;
}
- sna->render.white_image = pixman_image_create_solid_fill(&white);
sna->render.white_picture =
CreateSolidPicture(0, (xRenderColor *)&white, &error);
- return sna->render.white_image && sna->render.white_picture;
+ if (sna->render.white_picture == NULL)
+ goto bail;
+
+ return true;
bail:
sna_glyphs_close(sna);
- return FALSE;
+ return false;
}
static void
@@ -330,7 +350,7 @@ glyph_cache(ScreenPtr screen,
int size, mask, pos, s;
if (NO_GLYPH_CACHE)
- return FALSE;
+ return false;
if (glyph->info.width > GLYPH_MAX_SIZE ||
glyph->info.height > GLYPH_MAX_SIZE) {
@@ -340,7 +360,7 @@ glyph_cache(ScreenPtr screen,
pixmap->usage_hint = 0;
sna_pixmap_force_to_gpu(pixmap, MOVE_READ);
}
- return FALSE;
+ return false;
}
for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
@@ -404,7 +424,7 @@ glyph_cache(ScreenPtr screen,
glyph_cache_upload(cache, glyph, glyph_picture,
priv->coordinate.x, priv->coordinate.y);
- return TRUE;
+ return true;
}
static void apply_damage(struct sna_composite_op *op,
@@ -470,7 +490,7 @@ glyphs_to_dst(struct sna *sna,
int16_t x, y;
if (NO_GLYPHS_TO_DST)
- return FALSE;
+ return false;
memset(&tmp, 0, sizeof(tmp));
@@ -525,7 +545,7 @@ glyphs_to_dst(struct sna *sna,
0, 0, 0, 0, 0, 0,
0, 0,
&tmp))
- return FALSE;
+ return false;
glyph_atlas = priv.atlas;
}
@@ -603,7 +623,7 @@ next_glyph:
if (glyph_atlas)
tmp.done(sna, &tmp);
- return TRUE;
+ return true;
}
static bool
@@ -619,7 +639,7 @@ glyphs_slow(struct sna *sna,
int16_t x, y;
if (NO_GLYPHS_SLOW)
- return FALSE;
+ return false;
memset(&tmp, 0, sizeof(tmp));
@@ -675,7 +695,7 @@ glyphs_slow(struct sna *sna,
glyph->info.width,
glyph->info.height,
&tmp))
- return FALSE;
+ return false;
rects = REGION_RECTS(dst->pCompositeClip);
nrect = REGION_NUM_RECTS(dst->pCompositeClip);
@@ -726,7 +746,7 @@ next_glyph:
list++;
}
- return TRUE;
+ return true;
}
static bool
@@ -743,6 +763,37 @@ too_large(struct sna *sna, int width, int height)
height > sna->render.max_3d_size);
}
+static pixman_image_t *
+__sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
+{
+ pixman_image_t *image;
+ PicturePtr p;
+ int dx, dy;
+
+ p = GetGlyphPicture(g, s);
+ if (p == NULL)
+ return NULL;
+
+ image = image_from_pict(p, FALSE, &dx, &dy);
+ if (!image)
+ return NULL;
+
+ assert(dx == 0 && dy == 0);
+ return sna_glyph(g)->image = image;
+}
+
+static inline pixman_image_t *
+sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
+{
+ pixman_image_t *image;
+
+ image = sna_glyph(g)->image;
+ if (image == NULL)
+ image = __sna_glyph_get_image(g, s);
+
+ return image;
+}
+
static bool
glyphs_via_mask(struct sna *sna,
CARD8 op,
@@ -762,7 +813,7 @@ glyphs_via_mask(struct sna *sna,
BoxRec box;
if (NO_GLYPHS_VIA_MASK)
- return FALSE;
+ return false;
DBG(("%s(op=%d, src=(%d, %d), nlist=%d, dst=(%d, %d)+(%d, %d))\n",
__FUNCTION__, op, src_x, src_y, nlist,
@@ -770,7 +821,7 @@ glyphs_via_mask(struct sna *sna,
glyph_extents(nlist, list, glyphs, &box);
if (box.x2 <= box.x1 || box.y2 <= box.y1)
- return TRUE;
+ return true;
DBG(("%s: bounds=((%d, %d), (%d, %d))\n", __FUNCTION__,
box.x1, box.y1, box.x2, box.y2));
@@ -782,7 +833,7 @@ glyphs_via_mask(struct sna *sna,
box.x1, box.y1,
box.x2 - box.x1,
box.y2 - box.y1))
- return TRUE;
+ return true;
DBG(("%s: extents=((%d, %d), (%d, %d))\n", __FUNCTION__,
box.x1, box.y1, box.x2, box.y2));
@@ -799,7 +850,7 @@ glyphs_via_mask(struct sna *sna,
if (format->depth < 8) {
format = PictureMatchFormat(screen, 8, PICT_a8);
if (!format)
- return FALSE;
+ return false;
}
component_alpha = NeedsComponent(format->format);
@@ -818,7 +869,7 @@ upload:
format->depth,
KGEM_BUFFER_WRITE);
if (!pixmap)
- return FALSE;
+ return false;
mask_image =
pixman_image_create_bits(format->depth << 24 | format->format,
@@ -827,17 +878,88 @@ upload:
pixmap->devKind);
if (mask_image == NULL) {
screen->DestroyPixmap(pixmap);
- return FALSE;
+ return false;
}
memset(pixmap->devPrivate.ptr, 0, pixmap->devKind*height);
+#if HAS_PIXMAN_GLYPHS
+ {
+ pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
+ pixman_glyph_t *pglyphs = stack_glyphs;
+ pixman_glyph_cache_t *cache;
+ int count, n;
+
+ cache = sna->render.glyph_cache;
+ pixman_glyph_cache_freeze(cache);
+
+ count = 0;
+ for (n = 0; n < nlist; ++n)
+ count += list[n].len;
+ if (count > N_STACK_GLYPHS) {
+ pglyphs = malloc (count * sizeof(pixman_glyph_t));
+ if (pglyphs == NULL) {
+ screen->DestroyPixmap(pixmap);
+ return false;
+ }
+ }
+
+ count = 0;
+ do {
+ n = list->len;
+ x += list->xOff;
+ y += list->yOff;
+ while (n--) {
+ GlyphPtr g = *glyphs++;
+ const void *ptr;
+
+ if (g->info.width == 0 || g->info.height == 0)
+ goto next_image;
+
+ ptr = pixman_glyph_cache_lookup(cache, g, NULL);
+ if (ptr == NULL) {
+ pixman_image_t *glyph_image;
+
+ glyph_image = sna_glyph_get_image(g, screen);
+ if (glyph_image)
+ goto next_image;
+
+ ptr = pixman_glyph_cache_insert(cache, g, NULL,
+ g->info.x,
+ g->info.y,
+ glyph_image);
+ if (ptr == NULL)
+ goto next_image;
+ }
+
+ pglyphs[count].x = x;
+ pglyphs[count].y = y;
+ pglyphs[count].glyph = ptr;
+ count++;
+
+next_image:
+ x += g->info.xOff;
+ y += g->info.yOff;
+ }
+ list++;
+ } while (--nlist);
+
+ pixman_composite_glyphs_no_mask(PictOpAdd,
+ sna->render.white_image,
+ mask_image,
+ 0, 0,
+ 0, 0,
+ cache, count, pglyphs);
+ pixman_glyph_cache_thaw(cache);
+ if (pglyphs != stack_glyphs)
+ free(pglyphs);
+ }
+#else
do {
int n = list->len;
x += list->xOff;
y += list->yOff;
while (n--) {
GlyphPtr g = *glyphs++;
- PicturePtr picture;
pixman_image_t *glyph_image;
int16_t xi, yi;
@@ -855,23 +977,8 @@ upload:
yi + g->info.height <= 0)
goto next_image;
- glyph_image = sna_glyph(g)->image;
- if (glyph_image == NULL) {
- int dx, dy;
-
- picture = GetGlyphPicture(g, dst->pDrawable->pScreen);
- if (picture == NULL)
- goto next_image;
-
- glyph_image = image_from_pict(picture,
- FALSE,
- &dx, &dy);
- if (!glyph_image)
- goto next_image;
-
- assert(dx == 0 && dy == 0);
- sna_glyph(g)->image = glyph_image;
- }
+ glyph_image =
+ sna_glyph_get_image(g, dst->pDrawable->pScreen);
DBG(("%s: glyph to mask (%d, %d)x(%d, %d)\n",
__FUNCTION__,
@@ -908,6 +1015,7 @@ next_image:
}
list++;
} while (--nlist);
+#endif
pixman_image_unref(mask_image);
mask = CreatePicture(0, &pixmap->drawable,
@@ -915,7 +1023,7 @@ next_image:
&component_alpha, serverClient, &error);
screen->DestroyPixmap(pixmap);
if (!mask)
- return FALSE;
+ return false;
ValidatePicture(mask);
} else {
@@ -923,14 +1031,14 @@ next_image:
width, height, format->depth,
SNA_CREATE_SCRATCH);
if (!pixmap)
- return FALSE;
+ return false;
mask = CreatePicture(0, &pixmap->drawable,
format, CPComponentAlpha,
&component_alpha, serverClient, &error);
screen->DestroyPixmap(pixmap);
if (!mask)
- return FALSE;
+ return false;
ValidatePicture(mask);
if (!clear_pixmap(sna, pixmap)) {
@@ -999,7 +1107,7 @@ next_image:
DBG(("%s: fallback -- can not handle PictOpAdd of glyph onto mask!\n",
__FUNCTION__));
FreePicture(mask, 0);
- return FALSE;
+ return false;
}
glyph_atlas = this_atlas;
@@ -1037,7 +1145,7 @@ next_glyph:
width, height);
FreePicture(mask, 0);
- return TRUE;
+ return true;
}
static PictFormatPtr
@@ -1098,7 +1206,7 @@ glyphs_format(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
extents.y1 = y1;
extents.x2 = x2;
extents.y2 = y2;
- first = FALSE;
+ first = false;
} else {
/* Potential overlap?
* We cheat and ignore the boundary pixels, as
@@ -1148,6 +1256,160 @@ out:
return format;
}
+#if HAS_PIXMAN_GLYPHS
+static void
+glyphs_fallback(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ int src_x, int src_y,
+ int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+ struct sna *sna = to_sna_from_drawable(dst->pDrawable);
+ pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
+ pixman_glyph_t *pglyphs = stack_glyphs;
+ pixman_image_t *src_image, *dst_image;
+ pixman_glyph_cache_t *cache;
+ int dst_x = list->xOff, dst_y = list->yOff;
+ int src_dx, src_dy, dst_dx, dst_dy;
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ RegionRec region;
+ int x, y, count, n;
+
+ glyph_extents(nlist, list, glyphs, &region.extents);
+ if (region.extents.x2 <= region.extents.x1 ||
+ region.extents.y2 <= region.extents.y1)
+ return;
+
+ DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__,
+ region.extents.x1, region.extents.y1,
+ region.extents.x2, region.extents.y2));
+
+ region.data = NULL;
+ RegionTranslate(&region, dst->pDrawable->x, dst->pDrawable->y);
+ if (dst->pCompositeClip)
+ RegionIntersect(&region, &region, dst->pCompositeClip);
+ DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
+ __FUNCTION__,
+ RegionExtents(&region)->x1, RegionExtents(&region)->y1,
+ RegionExtents(&region)->x2, RegionExtents(&region)->y2));
+ if (!RegionNotEmpty(&region))
+ return;
+
+ if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
+ MOVE_READ | MOVE_WRITE))
+ return;
+ if (dst->alphaMap &&
+ !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable,
+ MOVE_READ | MOVE_WRITE))
+ return;
+
+ if (src->pDrawable) {
+ if (!sna_drawable_move_to_cpu(src->pDrawable,
+ MOVE_READ))
+ return;
+
+ if (src->alphaMap &&
+ !sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
+ MOVE_READ))
+ return;
+ }
+ RegionTranslate(&region, -dst->pDrawable->x, -dst->pDrawable->y);
+
+ cache = sna->render.glyph_cache;
+ pixman_glyph_cache_freeze(cache);
+
+ count = 0;
+ for (n = 0; n < nlist; ++n)
+ count += list[n].len;
+ if (count > N_STACK_GLYPHS) {
+ pglyphs = malloc (count * sizeof(pixman_glyph_t));
+ if (pglyphs == NULL)
+ goto out;
+ }
+
+ count = 0;
+ x = y = 0;
+ while (nlist--) {
+ n = list->len;
+ x += list->xOff;
+ y += list->yOff;
+ while (n--) {
+ GlyphPtr g = *glyphs++;
+ const void *ptr;
+
+ if (g->info.width == 0 || g->info.height == 0)
+ goto next;
+
+ ptr = pixman_glyph_cache_lookup(cache, g, NULL);
+ if (ptr == NULL) {
+ pixman_image_t *glyph_image;
+
+ glyph_image = sna_glyph_get_image(g, screen);
+ if (glyph_image)
+ goto next;
+
+ ptr = pixman_glyph_cache_insert(cache, g, NULL,
+ g->info.x,
+ g->info.y,
+ glyph_image);
+ if (ptr == NULL)
+ goto out;
+ }
+
+ pglyphs[count].x = x;
+ pglyphs[count].y = y;
+ pglyphs[count].glyph = ptr;
+ count++;
+
+next:
+ x += g->info.xOff;
+ y += g->info.yOff;
+ }
+ list++;
+ }
+
+ src_image = image_from_pict(src, FALSE, &src_dx, &src_dy);
+ if (src_image == NULL)
+ goto out;
+
+ dst_image = image_from_pict(dst, TRUE, &dst_dx, &dst_dy);
+ if (dst_image == NULL)
+ goto out_free_src;
+
+ if (mask_format &&
+ (op_is_bounded(op) || (nlist == 1 && list->len == 1)) &&
+ mask_format == glyphs_format(nlist, list, glyphs))
+ mask_format = NULL;
+
+ if (mask_format) {
+ pixman_composite_glyphs(op, src_image, dst_image,
+ mask_format->format | (mask_format->depth << 24),
+ src_x + src_dx + region.extents.x1 - dst_x,
+ src_y + src_dy + region.extents.y1 - dst_y,
+ region.extents.x1, region.extents.y1,
+ region.extents.x1 + dst_dx, region.extents.y1 + dst_dy,
+ region.extents.x2 - region.extents.x1,
+ region.extents.y2 - region.extents.y1,
+ cache, count, pglyphs);
+ } else {
+ pixman_composite_glyphs_no_mask(op, src_image, dst_image,
+ src_x + src_dx - dst_x, src_y + src_dy - dst_y,
+ dst_dx, dst_dy,
+ cache, count, pglyphs);
+ }
+
+ free_pixman_pict(dst, dst_image);
+
+out_free_src:
+ free_pixman_pict(src, src_image);
+
+out:
+ pixman_glyph_cache_thaw(cache);
+ if (pglyphs != stack_glyphs)
+ free(pglyphs);
+}
+#else
static void
glyphs_fallback(CARD8 op,
PicturePtr src,
@@ -1160,19 +1422,21 @@ glyphs_fallback(CARD8 op,
GlyphPtr *glyphs)
{
struct sna *sna = to_sna_from_drawable(dst->pDrawable);
+ ScreenPtr screen = dst->pDrawable->pScreen;
pixman_image_t *dst_image, *mask_image, *src_image;
int dx, dy, x, y;
- BoxRec box;
RegionRec region;
- glyph_extents(nlist, list, glyphs, &box);
- if (box.x2 <= box.x1 || box.y2 <= box.y1)
+ glyph_extents(nlist, list, glyphs, &region.extents);
+ if (region.extents.x2 <= region.extents.x1 ||
+ region.extents.y2 <= region.extents.y1)
return;
- DBG(("%s: (%d, %d), (%d, %d)\n",
- __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
+ DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__,
+ region.extents.x1, region.extents.y1,
+ region.extents.x2, region.extents.y2));
- RegionInit(&region, &box, 0);
+ region.data = NULL;
RegionTranslate(&region, dst->pDrawable->x, dst->pDrawable->y);
if (dst->pCompositeClip)
RegionIntersect(&region, &region, dst->pCompositeClip);
@@ -1267,23 +1531,9 @@ glyphs_fallback(CARD8 op,
if (g->info.width == 0 || g->info.height == 0)
goto next_glyph;
- glyph_image = sna_glyph(g)->image;
- if (glyph_image == NULL) {
- PicturePtr picture;
- int gx, gy;
-
- picture = GetGlyphPicture(g, dst->pDrawable->pScreen);
- if (picture == NULL)
- goto next_glyph;
-
- glyph_image = image_from_pict(picture, FALSE,
- &gx, &gy);
- if (!glyph_image)
- goto next_glyph;
-
- assert(gx == 0 && gy == 0);
- sna_glyph(g)->image = glyph_image;
- }
+ glyph_image = sna_glyph_get_image(g, screen);
+ if (glyph_image == NULL)
+ goto next_glyph;
if (mask_format) {
DBG(("%s: glyph+(%d,%d) to mask (%d, %d)x(%d, %d)\n",
@@ -1376,6 +1626,7 @@ cleanup_dst:
cleanup_region:
RegionUninit(&region);
}
+#endif
void
sna_glyphs(CARD8 op,
@@ -1470,6 +1721,10 @@ sna_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
struct sna_glyph *priv = sna_glyph(glyph);
if (priv->image) {
+#if HAS_PIXMAN_GLYPHS
+ struct sna *sna = to_sna_from_screen(screen);
+ pixman_glyph_cache_remove(sna->render.glyph_cache, glyph, NULL);
+#endif
pixman_image_unref(priv->image);
priv->image = NULL;
}
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index b003e7b6..364492f5 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -280,6 +280,9 @@ struct sna_render {
} glyph[2];
pixman_image_t *white_image;
PicturePtr white_picture;
+#if HAS_PIXMAN_GLYPHS
+ pixman_glyph_cache_t *glyph_cache;
+#endif
uint16_t vertex_start;
uint16_t vertex_index;