summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-12-08 12:34:34 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2011-12-08 12:34:52 +0000
commite5bc0c823b8fd46b3f851c5e9a4b4de39cda9a91 (patch)
tree4fac7f8d9b301bef3171641b64b380938559b7a5
parent874c722c86b06ac0aa10e6943d3faf76fcb751be (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.c108
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,