diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-08 12:34:34 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-08 12:34:52 +0000 |
commit | e5bc0c823b8fd46b3f851c5e9a4b4de39cda9a91 (patch) | |
tree | 4fac7f8d9b301bef3171641b64b380938559b7a5 | |
parent | 874c722c86b06ac0aa10e6943d3faf76fcb751be (diff) |
sna/gen2: Avoid readbacks for unsupported sources
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/gen2_render.c | 108 |
1 files changed, 104 insertions, 4 deletions
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c index e97e2d70..d35f2da5 100644 --- a/src/sna/gen2_render.c +++ b/src/sna/gen2_render.c @@ -1238,6 +1238,109 @@ try_blt(struct sna *sna, return is_cpu(source->pDrawable); } +static bool +is_solid(PicturePtr picture) +{ + return picture->pDrawable->width == 1 && + picture->pDrawable->height == 1 && + picture->repeat; +} + +static bool +is_gradient(PicturePtr picture) +{ + if (picture->pDrawable) + return FALSE; + + return picture->pSourcePict->type != SourcePictTypeSolidFill; +} + +static bool +source_fallback(PicturePtr p) +{ + return is_gradient(p) || !gen2_check_filter(p) || !gen2_check_repeat(p); +} + +static bool +gen2_composite_fallback(struct sna *sna, + PicturePtr src, + PicturePtr mask, + PicturePtr dst) +{ + struct sna_pixmap *priv; + PixmapPtr src_pixmap; + PixmapPtr mask_pixmap; + PixmapPtr dst_pixmap; + + if (!gen2_check_dst_format(dst->format)) { + DBG(("%s: unknown destination format: %d\n", + __FUNCTION__, dst->format)); + return TRUE; + } + + dst_pixmap = get_drawable_pixmap(dst->pDrawable); + src_pixmap = src->pDrawable ? get_drawable_pixmap(src->pDrawable) : NULL; + mask_pixmap = (mask && mask->pDrawable) ? get_drawable_pixmap(mask->pDrawable) : NULL; + + /* If we are using the destination as a source and need to + * readback in order to upload the source, do it all + * on the cpu. + */ + if (src_pixmap == dst_pixmap && source_fallback(src)) { + DBG(("%s: src is dst and will fallback\n",__FUNCTION__)); + return TRUE; + } + if (mask_pixmap == dst_pixmap && source_fallback(mask)) { + DBG(("%s: mask is dst and will fallback\n",__FUNCTION__)); + return TRUE; + } + + /* If anything is on the GPU, push everything out to the GPU */ + priv = sna_pixmap(dst_pixmap); + if (priv && priv->gpu_damage) { + DBG(("%s: dst is already on the GPU, try to use GPU\n", + __FUNCTION__)); + return FALSE; + } + + if (src_pixmap && !is_solid(src) && !source_fallback(src)) { + priv = sna_pixmap(src_pixmap); + if (priv && priv->gpu_damage) { + DBG(("%s: src is already on the GPU, try to use GPU\n", + __FUNCTION__)); + return FALSE; + } + } + if (mask_pixmap && !is_solid(mask) && !source_fallback(mask)) { + priv = sna_pixmap(mask_pixmap); + if (priv && priv->gpu_damage) { + DBG(("%s: mask is already on the GPU, try to use GPU\n", + __FUNCTION__)); + return FALSE; + } + } + + /* However if the dst is not on the GPU and we need to + * render one of the sources using the CPU, we may + * as well do the entire operation in place onthe CPU. + */ + if (source_fallback(src)) { + DBG(("%s: dst is on the CPU and src will fallback\n", + __FUNCTION__)); + return TRUE; + } + + if (mask && source_fallback(mask)) { + DBG(("%s: dst is on the CPU and mask will fallback\n", + __FUNCTION__)); + return TRUE; + } + + DBG(("%s: dst is not on the GPU and the operation should not fallback\n", + __FUNCTION__)); + return FALSE; +} + static Bool gen2_render_composite(struct sna *sna, uint8_t op, @@ -1282,11 +1385,8 @@ gen2_render_composite(struct sna *sna, tmp)) return TRUE; - if (!gen2_check_dst_format(dst->format)) { - DBG(("%s: fallback due to unhandled dst format: %x\n", - __FUNCTION__, dst->format)); + if (gen2_composite_fallback(sna, src, mask, dst)) return FALSE; - } if (need_tiling(sna, width, height)) return sna_tiling_composite(op, src, mask, dst, |