diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-08 12:35:54 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-08 12:35:54 +0000 |
commit | 440ac68ec074e82818713773f3e2cb5d363862aa (patch) | |
tree | f9d3ffec61a35de384b4f481f9301f6693dd68b9 | |
parent | bc68211d18356c4a0e011ac360665d600de9fa30 (diff) |
sna/gen6: Reduce dst readbacks for unsupported sources
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/gen6_render.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index 5a889e75..cb624635 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -2081,6 +2081,109 @@ try_blt(struct sna *sna, int width, int height) return FALSE; } +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) || !gen6_check_filter(p) || !gen6_check_repeat(p); +} + +static bool +gen6_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 (!gen6_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 gen6_render_composite(struct sna *sna, uint8_t op, @@ -2119,6 +2222,9 @@ gen6_render_composite(struct sna *sna, width, height, tmp)) return TRUE; + if (gen6_composite_fallback(sna, src, mask, dst)) + return FALSE; + if (need_tiling(sna, width, height)) return sna_tiling_composite(op, src, mask, dst, src_x, src_y, @@ -2482,6 +2588,9 @@ gen6_render_composite_spans(struct sna *sna, if (need_tiling(sna, width, height)) return FALSE; + if (gen6_composite_fallback(sna, src, NULL, dst)) + return FALSE; + tmp->base.op = op; if (!gen6_composite_set_target(&tmp->base, dst)) return FALSE; |