summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-03-25 21:25:15 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-03-25 23:04:58 +0100
commit62f9833298ea936eaefe973eca04b1dde858fbd8 (patch)
tree7600da2dbdfab43d458de67cd87707cd7cad7e8c
parent25807f472d051163ed96556a409110fa405c24d1 (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.c24
-rw-r--r--src/sna/gen3_render.c29
-rw-r--r--src/sna/gen4_render.c21
-rw-r--r--src/sna/gen5_render.c24
-rw-r--r--src/sna/gen6_render.c24
-rw-r--r--src/sna/gen7_render.c24
-rw-r--r--src/sna/sna_render.c86
-rw-r--r--src/sna/sna_render.h8
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,