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>
This commit is contained in:
Chris Wilson 2012-03-25 21:25:15 +01:00
parent 25807f472d
commit 62f9833298
8 changed files with 201 additions and 39 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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;

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -1368,6 +1368,92 @@ sna_render_picture_flatten(struct sna *sna,
return 1;
}
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,

View File

@ -614,6 +614,14 @@ sna_render_picture_extract(struct sna *sna,
int16_t w, int16_t h,
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,