diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-03-25 21:25:15 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-03-25 23:04:58 +0100 |
commit | 62f9833298ea936eaefe973eca04b1dde858fbd8 (patch) | |
tree | 7600da2dbdfab43d458de67cd87707cd7cad7e8c | |
parent | 25807f472d051163ed96556a409110fa405c24d1 (diff) |
sna/gen2+: Approximate expensive gradients when using imprecise rendering
If we lack the ability to use a shader to compute the gradients
per-pixel, we need to use pixman to render a fallback texture. We can
reduce the size of this texture and upsample to reduce the cost with
hopefully imperceptible loss of quality.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/gen2_render.c | 24 | ||||
-rw-r--r-- | src/sna/gen3_render.c | 29 | ||||
-rw-r--r-- | src/sna/gen4_render.c | 21 | ||||
-rw-r--r-- | src/sna/gen5_render.c | 24 | ||||
-rw-r--r-- | src/sna/gen6_render.c | 24 | ||||
-rw-r--r-- | src/sna/gen7_render.c | 24 | ||||
-rw-r--r-- | src/sna/sna_render.c | 86 | ||||
-rw-r--r-- | src/sna/sna_render.h | 8 |
8 files changed, 201 insertions, 39 deletions
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c index 6907dd61..0ad346ef 100644 --- a/src/sna/gen2_render.c +++ b/src/sna/gen2_render.c @@ -1310,7 +1310,8 @@ gen2_composite_picture(struct sna *sna, struct sna_composite_channel *channel, int x, int y, int w, int h, - int dst_x, int dst_y) + int dst_x, int dst_y, + bool precise) { PixmapPtr pixmap; uint32_t color; @@ -1343,6 +1344,8 @@ gen2_composite_picture(struct sna *sna, } if (picture->pDrawable == NULL) { + int ret; + if (picture->pSourcePict->type == SourcePictTypeLinear) return gen2_composite_linear_init(sna, picture, channel, x, y, @@ -1351,8 +1354,14 @@ gen2_composite_picture(struct sna *sna, DBG(("%s -- fallback, unhandled source %d\n", __FUNCTION__, picture->pSourcePict->type)); - return sna_render_picture_fixup(sna, picture, channel, - x, y, w, h, dst_x, dst_y); + ret = -1; + if (!precise) + ret = sna_render_picture_approximate_gradient(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + if (ret == -1) + ret = sna_render_picture_fixup(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + return ret; } if (picture->alphaMap) { @@ -1765,7 +1774,8 @@ gen2_render_composite(struct sna *sna, switch (gen2_composite_picture(sna, src, &tmp->src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: @@ -1781,7 +1791,8 @@ gen2_render_composite(struct sna *sna, switch (gen2_composite_picture(sna, mask, &tmp->mask, mask_x, mask_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_src; case 0: @@ -2229,7 +2240,8 @@ gen2_render_composite_spans(struct sna *sna, switch (gen2_composite_picture(sna, src, &tmp->base.src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c index b2367611..e7980962 100644 --- a/src/sna/gen3_render.c +++ b/src/sna/gen3_render.c @@ -2194,7 +2194,7 @@ gen3_init_linear(struct sna *sna, op->u.gen3.constants[n++] = 0; if (!gen3_gradient_setup(sna, picture, channel, ox, oy)) - return 0; + return -1; channel->u.gen3.type = SHADER_LINEAR; op->u.gen3.num_constants = n; @@ -2250,7 +2250,7 @@ gen3_init_radial(struct sna *sna, } if (!gen3_gradient_setup(sna, picture, channel, ox, oy)) - return 0; + return -1; channel->u.gen3.type = SHADER_RADIAL; op->u.gen3.num_constants = n; @@ -2285,7 +2285,8 @@ gen3_composite_picture(struct sna *sna, struct sna_composite_channel *channel, int16_t x, int16_t y, int16_t w, int16_t h, - int16_t dst_x, int16_t dst_y) + int16_t dst_x, int16_t dst_y, + bool precise) { PixmapPtr pixmap; uint32_t color; @@ -2298,7 +2299,7 @@ gen3_composite_picture(struct sna *sna, if (picture->pDrawable == NULL) { SourcePict *source = picture->pSourcePict; - int ret = 0; + int ret = -1; switch (source->type) { case SourcePictTypeSolidFill: @@ -2316,9 +2317,14 @@ gen3_composite_picture(struct sna *sna, break; } - if (ret == 0) - ret = sna_render_picture_fixup(sna, picture, channel, - x, y, w, h, dst_x, dst_y); + if (ret == -1) { + if (!precise) + ret = sna_render_picture_approximate_gradient(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + if (ret == -1) + ret = sna_render_picture_fixup(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + } return ret; } @@ -2815,7 +2821,8 @@ gen3_render_composite(struct sna *sna, switch (gen3_composite_picture(sna, src, tmp, &tmp->src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: @@ -2840,7 +2847,8 @@ gen3_render_composite(struct sna *sna, switch (gen3_composite_picture(sna, mask, tmp, &tmp->mask, mask_x, mask_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_src; case 0: @@ -3379,7 +3387,8 @@ gen3_render_composite_spans(struct sna *sna, switch (gen3_composite_picture(sna, src, &tmp->base, &tmp->base.src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c index def5d19a..2e78a921 100644 --- a/src/sna/gen4_render.c +++ b/src/sna/gen4_render.c @@ -1957,7 +1957,8 @@ gen4_composite_picture(struct sna *sna, struct sna_composite_channel *channel, int x, int y, int w, int h, - int dst_x, int dst_y) + int dst_x, int dst_y, + bool precise) { PixmapPtr pixmap; uint32_t color; @@ -1973,6 +1974,8 @@ gen4_composite_picture(struct sna *sna, return gen4_composite_solid_init(sna, channel, color); if (picture->pDrawable == NULL) { + int ret; + if (picture->pSourcePict->type == SourcePictTypeLinear) return gen4_composite_linear_init(sna, picture, channel, x, y, @@ -1980,8 +1983,14 @@ gen4_composite_picture(struct sna *sna, dst_x, dst_y); DBG(("%s -- fixup, gradient\n", __FUNCTION__)); - return sna_render_picture_fixup(sna, picture, channel, - x, y, w, h, dst_x, dst_y); + ret = -1; + if (!precise) + ret = sna_render_picture_approximate_gradient(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + if (ret == -1) + ret = sna_render_picture_fixup(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + return ret; } if (picture->alphaMap) { @@ -2404,7 +2413,8 @@ gen4_render_composite(struct sna *sna, switch (gen4_composite_picture(sna, src, &tmp->src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: DBG(("%s: failed to prepare source\n", __FUNCTION__)); goto cleanup_dst; @@ -2449,7 +2459,8 @@ gen4_render_composite(struct sna *sna, switch (gen4_composite_picture(sna, mask, &tmp->mask, msk_x, msk_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: DBG(("%s: failed to prepare mask\n", __FUNCTION__)); goto cleanup_src; diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c index 565d22aa..c27accd7 100644 --- a/src/sna/gen5_render.c +++ b/src/sna/gen5_render.c @@ -1990,7 +1990,8 @@ gen5_composite_picture(struct sna *sna, struct sna_composite_channel *channel, int x, int y, int w, int h, - int dst_x, int dst_y) + int dst_x, int dst_y, + bool precise) { PixmapPtr pixmap; uint32_t color; @@ -2006,6 +2007,8 @@ gen5_composite_picture(struct sna *sna, return gen5_composite_solid_init(sna, channel, color); if (picture->pDrawable == NULL) { + int ret; + if (picture->pSourcePict->type == SourcePictTypeLinear) return gen5_composite_linear_init(sna, picture, channel, x, y, @@ -2013,8 +2016,14 @@ gen5_composite_picture(struct sna *sna, dst_x, dst_y); DBG(("%s -- fixup, gradient\n", __FUNCTION__)); - return sna_render_picture_fixup(sna, picture, channel, - x, y, w, h, dst_x, dst_y); + ret = -1; + if (!precise) + ret = sna_render_picture_approximate_gradient(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + if (ret == -1) + ret = sna_render_picture_fixup(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + return ret; } if (picture->alphaMap) { @@ -2444,7 +2453,8 @@ gen5_render_composite(struct sna *sna, switch (gen5_composite_picture(sna, src, &tmp->src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: DBG(("%s: failed to prepare source picture\n", __FUNCTION__)); goto cleanup_dst; @@ -2488,7 +2498,8 @@ gen5_render_composite(struct sna *sna, switch (gen5_composite_picture(sna, mask, &tmp->mask, msk_x, msk_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: DBG(("%s: failed to prepare mask picture\n", __FUNCTION__)); goto cleanup_src; @@ -2800,7 +2811,8 @@ gen5_render_composite_spans(struct sna *sna, switch (gen5_composite_picture(sna, src, &tmp->base.src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index fde07766..6f1b55a6 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -2165,7 +2165,8 @@ gen6_composite_picture(struct sna *sna, struct sna_composite_channel *channel, int x, int y, int w, int h, - int dst_x, int dst_y) + int dst_x, int dst_y, + bool precise) { PixmapPtr pixmap; uint32_t color; @@ -2181,6 +2182,8 @@ gen6_composite_picture(struct sna *sna, return gen6_composite_solid_init(sna, channel, color); if (picture->pDrawable == NULL) { + int ret; + if (picture->pSourcePict->type == SourcePictTypeLinear) return gen6_composite_linear_init(sna, picture, channel, x, y, @@ -2188,8 +2191,14 @@ gen6_composite_picture(struct sna *sna, dst_x, dst_y); DBG(("%s -- fixup, gradient\n", __FUNCTION__)); - return sna_render_picture_fixup(sna, picture, channel, - x, y, w, h, dst_x, dst_y); + ret = -1; + if (!precise) + ret = sna_render_picture_approximate_gradient(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + if (ret == -1) + ret = sna_render_picture_fixup(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + return ret; } if (picture->alphaMap) { @@ -2646,7 +2655,8 @@ gen6_render_composite(struct sna *sna, switch (gen6_composite_picture(sna, src, &tmp->src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: @@ -2702,7 +2712,8 @@ gen6_render_composite(struct sna *sna, switch (gen6_composite_picture(sna, mask, &tmp->mask, msk_x, msk_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_src; case 0: @@ -3089,7 +3100,8 @@ gen6_render_composite_spans(struct sna *sna, switch (gen6_composite_picture(sna, src, &tmp->base.src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c index 36ea8a1e..14911673 100644 --- a/src/sna/gen7_render.c +++ b/src/sna/gen7_render.c @@ -2270,7 +2270,8 @@ gen7_composite_picture(struct sna *sna, struct sna_composite_channel *channel, int x, int y, int w, int h, - int dst_x, int dst_y) + int dst_x, int dst_y, + bool precise) { PixmapPtr pixmap; uint32_t color; @@ -2286,6 +2287,8 @@ gen7_composite_picture(struct sna *sna, return gen7_composite_solid_init(sna, channel, color); if (picture->pDrawable == NULL) { + int ret; + if (picture->pSourcePict->type == SourcePictTypeLinear) return gen7_composite_linear_init(sna, picture, channel, x, y, @@ -2293,8 +2296,14 @@ gen7_composite_picture(struct sna *sna, dst_x, dst_y); DBG(("%s -- fixup, gradient\n", __FUNCTION__)); - return sna_render_picture_fixup(sna, picture, channel, - x, y, w, h, dst_x, dst_y); + ret = -1; + if (!precise) + ret = sna_render_picture_approximate_gradient(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + if (ret == -1) + ret = sna_render_picture_fixup(sna, picture, channel, + x, y, w, h, dst_x, dst_y); + return ret; } if (picture->alphaMap) { @@ -2732,7 +2741,8 @@ gen7_render_composite(struct sna *sna, switch (gen7_composite_picture(sna, src, &tmp->src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: @@ -2788,7 +2798,8 @@ gen7_render_composite(struct sna *sna, switch (gen7_composite_picture(sna, mask, &tmp->mask, msk_x, msk_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_src; case 0: @@ -3185,7 +3196,8 @@ gen7_render_composite_spans(struct sna *sna, switch (gen7_composite_picture(sna, src, &tmp->base.src, src_x, src_y, width, height, - dst_x, dst_y)) { + dst_x, dst_y, + dst->polyMode == PolyModePrecise)) { case -1: goto cleanup_dst; case 0: diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c index 542cdb95..d774a349 100644 --- a/src/sna/sna_render.c +++ b/src/sna/sna_render.c @@ -1369,6 +1369,92 @@ sna_render_picture_flatten(struct sna *sna, } int +sna_render_picture_approximate_gradient(struct sna *sna, + PicturePtr picture, + struct sna_composite_channel *channel, + int16_t x, int16_t y, + int16_t w, int16_t h, + int16_t dst_x, int16_t dst_y) +{ + pixman_image_t *dst, *src; + pixman_transform_t t; + int w2 = w/2, h2 = h/2; + int dx, dy; + void *ptr; + +#if NO_FIXUP + return -1; +#endif + + DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); + + if (w2 == 0 || h2 == 0) { + DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); + return -1; + } + if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) { + DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); + return -1; + } + + channel->pict_format = PIXMAN_a8r8g8b8; + channel->bo = kgem_create_buffer_2d(&sna->kgem, + w2, h2, 32, + KGEM_BUFFER_WRITE_INPLACE, + &ptr); + if (!channel->bo) { + DBG(("%s: failed to create upload buffer, using clear\n", + __FUNCTION__)); + return 0; + } + + dst = pixman_image_create_bits(PIXMAN_a8r8g8b8, + w2, h2, ptr, channel->bo->pitch); + if (!dst) { + kgem_bo_destroy(&sna->kgem, channel->bo); + return 0; + } + + src = image_from_pict(picture, FALSE, &dx, &dy); + if (src == NULL) { + pixman_image_unref(dst); + kgem_bo_destroy(&sna->kgem, channel->bo); + return 0; + } + + memset(&t, 0, sizeof(t)); + t.matrix[0][0] = (w << 16) / w2; + t.matrix[1][1] = (h << 16) / h2; + t.matrix[2][2] = 1 << 16; + if (picture->transform) + pixman_transform_multiply(&t, picture->transform, &t); + pixman_image_set_transform(src, &t); + + pixman_image_composite(PictOpSrc, src, NULL, dst, + x + dx, y + dy, + 0, 0, + 0, 0, + w2, h2); + free_pixman_pict(picture, src); + pixman_image_unref(dst); + + channel->width = w2; + channel->height = h2; + + channel->filter = PictFilterNearest; + channel->repeat = RepeatNone; + channel->is_affine = TRUE; + + channel->scale[0] = 1.f/w; + channel->scale[1] = 1.f/h; + channel->offset[0] = -dst_x; + channel->offset[1] = -dst_y; + channel->transform = NULL; + + return 1; +} + +int sna_render_picture_fixup(struct sna *sna, PicturePtr picture, struct sna_composite_channel *channel, diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h index 8d3d9e4f..a83f78ed 100644 --- a/src/sna/sna_render.h +++ b/src/sna/sna_render.h @@ -615,6 +615,14 @@ sna_render_picture_extract(struct sna *sna, int16_t dst_x, int16_t dst_y); int +sna_render_picture_approximate_gradient(struct sna *sna, + PicturePtr picture, + struct sna_composite_channel *channel, + int16_t x, int16_t y, + int16_t w, int16_t h, + int16_t dst_x, int16_t dst_y); + +int sna_render_picture_fixup(struct sna *sna, PicturePtr picture, struct sna_composite_channel *channel, |