diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-23 00:01:50 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-23 00:28:12 +0000 |
commit | 84d97bdba02b909369b54de21425ffc9f6ad581a (patch) | |
tree | a2f33adde3469fdc54846917ca9b545951eeb413 | |
parent | 281f620573917faef52d9226b12737ce1e2dffdc (diff) |
sna/gen2+: Reuse source channel for mask where possible
GTK+ has a clever trick for premultiplying its images by loading the
same pixel data into both the source and mask, and then performing the
composite. This causes us to upload the same pixel data twice!
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/gen2_render.c | 60 | ||||
-rw-r--r-- | src/sna/gen3_render.c | 69 | ||||
-rw-r--r-- | src/sna/gen4_render.c | 65 | ||||
-rw-r--r-- | src/sna/gen5_render.c | 67 | ||||
-rw-r--r-- | src/sna/gen6_render.c | 63 | ||||
-rw-r--r-- | src/sna/gen7_render.c | 63 | ||||
-rw-r--r-- | src/sna/sna.h | 27 |
7 files changed, 342 insertions, 72 deletions
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c index 519ba189..f1fdfd6f 100644 --- a/src/sna/gen2_render.c +++ b/src/sna/gen2_render.c @@ -1401,6 +1401,42 @@ gen2_composite_fallback(struct sna *sna, return FALSE; } +static int +reuse_source(struct sna *sna, + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y, + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y) +{ + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable) + return FALSE; + + DBG(("%s: mask reuses source drawable\n", __FUNCTION__)); + + if (src_x != msk_x || src_y != msk_y) + return FALSE; + + if (!sna_transform_equal(src->transform, mask->transform)) + return FALSE; + + if (!sna_picture_alphamap_equal(src, mask)) + return FALSE; + + if (!gen2_check_repeat(mask)) + return FALSE; + + if (!gen2_check_filter(mask)) + return FALSE; + + DBG(("%s: reusing source channel for mask with a twist\n", + __FUNCTION__)); + + *mc = *sc; + mc->repeat = mask->repeat ? mask->repeatType : RepeatNone; + mc->filter = mask->filter; + mc->pict_format = mask->format; + mc->bo = kgem_bo_reference(mc->bo); + return TRUE; +} + static Bool gen2_render_composite(struct sna *sna, uint8_t op, @@ -1493,16 +1529,20 @@ gen2_render_composite(struct sna *sna, } if (mask) { - switch (gen2_composite_picture(sna, mask, &tmp->mask, - mask_x, mask_y, - width, height, - dst_x, dst_y)) { - case -1: - goto cleanup_src; - case 0: - gen2_composite_solid_init(sna, &tmp->mask, 0); - case 1: - break; + if (!reuse_source(sna, + src, &tmp->src, src_x, src_y, + mask, &tmp->mask, mask_x, mask_y)) { + switch (gen2_composite_picture(sna, mask, &tmp->mask, + mask_x, mask_y, + width, height, + dst_x, dst_y)) { + case -1: + goto cleanup_src; + case 0: + gen2_composite_solid_init(sna, &tmp->mask, 0); + case 1: + break; + } } if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) { diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c index 12eebaab..5833c1fc 100644 --- a/src/sna/gen3_render.c +++ b/src/sna/gen3_render.c @@ -2394,6 +2394,43 @@ gen3_composite_fallback(struct sna *sna, return FALSE; } +static int +reuse_source(struct sna *sna, + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y, + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y) +{ + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable) + return FALSE; + + DBG(("%s: mask reuses source drawable\n", __FUNCTION__)); + + if (src_x != msk_x || src_y != msk_y) + return FALSE; + + if (!sna_transform_equal(src->transform, mask->transform)) + return FALSE; + + if (!sna_picture_alphamap_equal(src, mask)) + return FALSE; + + if (!gen3_check_repeat(mask)) + return FALSE; + + if (!gen3_check_filter(mask->filter)) + return FALSE; + + DBG(("%s: reusing source channel for mask with a twist\n", + __FUNCTION__)); + + *mc = *sc; + mc->repeat = gen3_texture_repeat(mask->repeat ? mask->repeatType : RepeatNone); + mc->filter = gen3_filter(mask->filter); + mc->pict_format = mask->format; + gen3_composite_channel_set_format(mc, mask->format); + mc->bo = kgem_bo_reference(mc->bo); + return TRUE; +} + static Bool gen3_render_composite(struct sna *sna, uint8_t op, @@ -2499,20 +2536,24 @@ gen3_render_composite(struct sna *sna, tmp->need_magic_ca_pass = FALSE; tmp->has_component_alpha = FALSE; if (mask && tmp->src.u.gen3.type != SHADER_ZERO) { - tmp->mask.u.gen3.type = SHADER_TEXTURE; - DBG(("%s: preparing mask\n", __FUNCTION__)); - switch (gen3_composite_picture(sna, mask, tmp, &tmp->mask, - mask_x, mask_y, - width, height, - dst_x, dst_y)) { - case -1: - goto cleanup_src; - case 0: - tmp->mask.u.gen3.type = SHADER_ZERO; - break; - case 1: - gen3_composite_channel_convert(&tmp->mask); - break; + if (!reuse_source(sna, + src, &tmp->src, src_x, src_y, + mask, &tmp->mask, mask_x, mask_y)) { + tmp->mask.u.gen3.type = SHADER_TEXTURE; + DBG(("%s: preparing mask\n", __FUNCTION__)); + switch (gen3_composite_picture(sna, mask, tmp, &tmp->mask, + mask_x, mask_y, + width, height, + dst_x, dst_y)) { + case -1: + goto cleanup_src; + case 0: + tmp->mask.u.gen3.type = SHADER_ZERO; + break; + case 1: + gen3_composite_channel_convert(&tmp->mask); + break; + } } DBG(("%s: mask type=%d\n", __FUNCTION__, tmp->mask.u.gen3.type)); diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c index 6ccddd20..9f15b3c4 100644 --- a/src/sna/gen4_render.c +++ b/src/sna/gen4_render.c @@ -2008,6 +2008,43 @@ gen4_composite_fallback(struct sna *sna, return FALSE; } +static int +reuse_source(struct sna *sna, + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y, + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y) +{ + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable) + return FALSE; + + DBG(("%s: mask reuses source drawable\n", __FUNCTION__)); + + if (src_x != msk_x || src_y != msk_y) + return FALSE; + + if (!sna_transform_equal(src->transform, mask->transform)) + return FALSE; + + if (!sna_picture_alphamap_equal(src, mask)) + return FALSE; + + if (!gen4_check_repeat(mask)) + return FALSE; + + if (!gen4_check_filter(mask)) + return FALSE; + + DBG(("%s: reusing source channel for mask with a twist\n", + __FUNCTION__)); + + *mc = *sc; + mc->repeat = gen4_repeat(mask->repeat ? mask->repeatType : RepeatNone); + mc->filter = gen4_filter(mask->filter); + mc->pict_format = mask->format; + mc->card_format = gen4_get_card_format(mask->format); + mc->bo = kgem_bo_reference(mc->bo); + return TRUE; +} + static Bool gen4_render_composite(struct sna *sna, uint8_t op, @@ -2109,18 +2146,22 @@ gen4_render_composite(struct sna *sna, } } - switch (gen4_composite_picture(sna, mask, &tmp->mask, - msk_x, msk_y, - width, height, - dst_x, dst_y)) { - case -1: - DBG(("%s: failed to prepare mask\n", __FUNCTION__)); - goto cleanup_src; - case 0: - gen4_composite_solid_init(sna, &tmp->mask, 0); - case 1: - gen4_composite_channel_convert(&tmp->mask); - break; + if (!reuse_source(sna, + src, &tmp->src, src_x, src_y, + mask, &tmp->mask, msk_x, msk_y)) { + switch (gen4_composite_picture(sna, mask, &tmp->mask, + msk_x, msk_y, + width, height, + dst_x, dst_y)) { + case -1: + DBG(("%s: failed to prepare mask\n", __FUNCTION__)); + goto cleanup_src; + case 0: + gen4_composite_solid_init(sna, &tmp->mask, 0); + case 1: + gen4_composite_channel_convert(&tmp->mask); + break; + } } tmp->is_affine &= tmp->mask.is_affine; diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c index 180b561a..0b422726 100644 --- a/src/sna/gen5_render.c +++ b/src/sna/gen5_render.c @@ -2050,6 +2050,43 @@ gen5_composite_fallback(struct sna *sna, return FALSE; } +static int +reuse_source(struct sna *sna, + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y, + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y) +{ + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable) + return FALSE; + + DBG(("%s: mask reuses source drawable\n", __FUNCTION__)); + + if (src_x != msk_x || src_y != msk_y) + return FALSE; + + if (!sna_transform_equal(src->transform, mask->transform)) + return FALSE; + + if (!sna_picture_alphamap_equal(src, mask)) + return FALSE; + + if (!gen5_check_repeat(mask)) + return FALSE; + + if (!gen5_check_filter(mask)) + return FALSE; + + DBG(("%s: reusing source channel for mask with a twist\n", + __FUNCTION__)); + + *mc = *sc; + mc->repeat = gen5_repeat(mask->repeat ? mask->repeatType : RepeatNone); + mc->filter = gen5_filter(mask->filter); + mc->pict_format = mask->format; + mc->card_format = gen5_get_card_format(mask->format); + mc->bo = kgem_bo_reference(mc->bo); + return TRUE; +} + static Bool gen5_render_composite(struct sna *sna, uint8_t op, @@ -2152,19 +2189,23 @@ gen5_render_composite(struct sna *sna, } } - DBG(("%s: preparing mask\n", __FUNCTION__)); - switch (gen5_composite_picture(sna, mask, &tmp->mask, - msk_x, msk_y, - width, height, - dst_x, dst_y)) { - case -1: - DBG(("%s: failed to prepare mask picture\n", __FUNCTION__)); - goto cleanup_src; - case 0: - gen5_composite_solid_init(sna, &tmp->mask, 0); - case 1: - gen5_composite_channel_convert(&tmp->mask); - break; + if (!reuse_source(sna, + src, &tmp->src, src_x, src_y, + mask, &tmp->mask, msk_x, msk_y)) { + DBG(("%s: preparing mask\n", __FUNCTION__)); + switch (gen5_composite_picture(sna, mask, &tmp->mask, + msk_x, msk_y, + width, height, + dst_x, dst_y)) { + case -1: + DBG(("%s: failed to prepare mask picture\n", __FUNCTION__)); + goto cleanup_src; + case 0: + gen5_composite_solid_init(sna, &tmp->mask, 0); + case 1: + gen5_composite_channel_convert(&tmp->mask); + break; + } } tmp->is_affine &= tmp->mask.is_affine; diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index 8e7ea156..985bb90b 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -2225,6 +2225,43 @@ gen6_composite_fallback(struct sna *sna, return FALSE; } +static int +reuse_source(struct sna *sna, + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y, + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y) +{ + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable) + return FALSE; + + DBG(("%s: mask reuses source drawable\n", __FUNCTION__)); + + if (src_x != msk_x || src_y != msk_y) + return FALSE; + + if (!sna_transform_equal(src->transform, mask->transform)) + return FALSE; + + if (!sna_picture_alphamap_equal(src, mask)) + return FALSE; + + if (!gen6_check_repeat(mask)) + return FALSE; + + if (!gen6_check_filter(mask)) + return FALSE; + + DBG(("%s: reusing source channel for mask with a twist\n", + __FUNCTION__)); + + *mc = *sc; + mc->repeat = gen6_repeat(mask->repeat ? mask->repeatType : RepeatNone); + mc->filter = gen6_filter(mask->filter); + mc->pict_format = mask->format; + mc->card_format = gen6_get_card_format(mask->format); + mc->bo = kgem_bo_reference(mc->bo); + return TRUE; +} + static Bool gen6_render_composite(struct sna *sna, uint8_t op, @@ -2347,17 +2384,21 @@ gen6_render_composite(struct sna *sna, } } - switch (gen6_composite_picture(sna, mask, &tmp->mask, - msk_x, msk_y, - width, height, - dst_x, dst_y)) { - case -1: - goto cleanup_src; - case 0: - gen6_composite_solid_init(sna, &tmp->mask, 0); - case 1: - gen6_composite_channel_convert(&tmp->mask); - break; + if (!reuse_source(sna, + src, &tmp->src, src_x, src_y, + mask, &tmp->mask, msk_x, msk_y)) { + switch (gen6_composite_picture(sna, mask, &tmp->mask, + msk_x, msk_y, + width, height, + dst_x, dst_y)) { + case -1: + goto cleanup_src; + case 0: + gen6_composite_solid_init(sna, &tmp->mask, 0); + case 1: + gen6_composite_channel_convert(&tmp->mask); + break; + } } tmp->is_affine &= tmp->mask.is_affine; diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c index 58647f74..5eac9bf6 100644 --- a/src/sna/gen7_render.c +++ b/src/sna/gen7_render.c @@ -2338,6 +2338,43 @@ gen7_composite_fallback(struct sna *sna, return FALSE; } +static int +reuse_source(struct sna *sna, + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y, + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y) +{ + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable) + return FALSE; + + DBG(("%s: mask reuses source drawable\n", __FUNCTION__)); + + if (src_x != msk_x || src_y != msk_y) + return FALSE; + + if (!sna_transform_equal(src->transform, mask->transform)) + return FALSE; + + if (!sna_picture_alphamap_equal(src, mask)) + return FALSE; + + if (!gen7_check_repeat(mask)) + return FALSE; + + if (!gen7_check_filter(mask)) + return FALSE; + + DBG(("%s: reusing source channel for mask with a twist\n", + __FUNCTION__)); + + *mc = *sc; + mc->repeat = gen7_repeat(mask->repeat ? mask->repeatType : RepeatNone); + mc->filter = gen7_filter(mask->filter); + mc->pict_format = mask->format; + mc->card_format = gen7_get_card_format(mask->format); + mc->bo = kgem_bo_reference(mc->bo); + return TRUE; +} + static Bool gen7_render_composite(struct sna *sna, uint8_t op, @@ -2460,17 +2497,21 @@ gen7_render_composite(struct sna *sna, } } - switch (gen7_composite_picture(sna, mask, &tmp->mask, - msk_x, msk_y, - width, height, - dst_x, dst_y)) { - case -1: - goto cleanup_src; - case 0: - gen7_composite_solid_init(sna, &tmp->mask, 0); - case 1: - gen7_composite_channel_convert(&tmp->mask); - break; + if (!reuse_source(sna, + src, &tmp->src, src_x, src_y, + mask, &tmp->mask, msk_x, msk_y)) { + switch (gen7_composite_picture(sna, mask, &tmp->mask, + msk_x, msk_y, + width, height, + dst_x, dst_y)) { + case -1: + goto cleanup_src; + case 0: + gen7_composite_solid_init(sna, &tmp->mask, 0); + case 1: + gen7_composite_channel_convert(&tmp->mask); + break; + } } tmp->is_affine &= tmp->mask.is_affine; diff --git a/src/sna/sna.h b/src/sna/sna.h index 1fa31222..1ee4da20 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -507,7 +507,7 @@ _sna_get_transformed_coordinates(int x, int y, void sna_get_transformed_coordinates(int x, int y, - const PictTransform *transform, + const PictTransform *transform, float *x_out, float *y_out); Bool @@ -521,6 +521,31 @@ Bool sna_transform_is_integer_translation(const PictTransform *t, Bool sna_transform_is_translation(const PictTransform *t, pixman_fixed_t *tx, pixman_fixed_t *ty); +static inline bool +sna_transform_equal(const PictTransform *a, const PictTransform *b) +{ + if (a == b) + return true; + + if (a == NULL || b == NULL) + return false; + + return memcmp(a, b, sizeof(*a)) == 0; +} + +static inline bool +sna_picture_alphamap_equal(PicturePtr a, PicturePtr b) +{ + if (a->alphaMap != b->alphaMap) + return false; + + if (a->alphaMap) + return false; + + return (a->alphaOrigin.x == b->alphaOrigin.x && + a->alphaOrigin.y == b->alphaOrigin.y); +} + static inline bool wedged(struct sna *sna) { return unlikely(sna->kgem.wedged); |