# [Pixman] [PATCH 0/2] 7-bit bilinear interpolation precision

Søren Sandmann sandmann at cs.au.dk
Wed Jun 27 09:08:29 PDT 2012

```Siarhei Siamashka <siarhei.siamashka at gmail.com> writes:

> There is also one thing to investigate. It was likely also a problem
> earlier, but may become worse when going to lower interpolation
> precision. Right now the position between pixels is rounded down by
> throwing away lowest bits when converting it to bilinear weight. It
> may potentially cause image drift to the left/upper side if the image
> is scaled up/down repeatedly really a lot. Maybe pixman_fixed_1 / 2
> constant needs to be adjusted here (and in the other places too) to
> ensure more correct rounding:
>     http://cgit.freedesktop.org/pixman/tree/pixman/pixman-inlines.h?id=pixman-0.26.0#n811
> But I guess it's better to write a test program to check whether such
> effect exists.

The pixman_fixed_1 / 2 constant actually has to do with coordinate
systems. If pixels are considered squares, then pixman's coordinate
system is such that (0.5, 0.5) is the center of the top left pixel. Ie.,
the asterixes below have coordinates at the half-integers.

(0, 0)
+----------------------------------
| * | * |
+---+---+-----
| * | * |
+---+---+
|   |

When compositing, pixman is given a rectangle (dst_x, dst_y, width,
height) with integer coordinates. To compute the result for the top left
pixel, in principle, pixman should do this:

1. Add 0.5, 0.5 to dst_x, dst_y to get the coordinate of the first
pixel
2. Transform those coordinates to get a source location
3. If a nearest filter is used, round to closest half-integer (down if
they are equal)
4. Subtract 0.5, 0.5 to get x and y integers that can be used to
compute an index into the bits[] array.

For the non-transformed blitters, all of this disappears and becomes
just an offset that can be computed upfront. But when there is a
transformation, the full computation must be carried out. The
pixman_fixed_1/2 constant used all over the place is just the 0.5 in
step 1.

For the nearest filter, step 3 and step 4 can be simplified to simply
subtracting pixman_fixed_e (to ensure we round down), and then
truncating.

For bilinear filtering, the question of rounding down is mostly
irrelevant because we need both the pixel below and above. In this case
step 3 and 4 become simply a truncation.

The question of rounding the bilinear interpolation location is
separate. It's true that the truncation of the fraction can lead to
shifts of a 128th of pixel, and maybe this should be fixed.

A simple solution would be to just add 0x80 or 0x40 before shifting, but
it might be possible do that only once per scanline, or even once per
composite operation for scalings. I doubt that it can be done easily by
modifying the pixman_fixed_1/2 constant though.

Søren
```