[Pixman] [PATCH 5/5] test: Add a new benchmarker targeting affine operations

Ben Avison bavison at riscosopen.org
Wed Apr 15 09:03:43 PDT 2015

On Wed, 15 Apr 2015 10:39:54 +0100,
Pekka Paalanen <ppaalanen at gmail.com> wrote:

> On Tue, 14 Apr 2015 19:00:58 +0100
> "Ben Avison" <bavison at riscosopen.org> wrote:
>> Assume the reasonable case that you want to plot the whole of
>> an image of size x,y at a size m,n. You need to set the diagonals of
>> the transform to
>> floor(pixman_fixed_1*(x-1)/(m-1))
>> floor(pixman_fixed_1*(y-1)/(n-1))
>> 1
>> and then solve for
>>     / 0.5 \   / 0.5 \
>> T . | 0.5 | = | 0.5 |
>>     \ 1   /   \ 1   /
>> to find the translation coefficients that will ensure the top-left
>> source pixel aligns exactly to the top-left destination pixel.
> Urgh, I don't think we account for *that* in e.g. Weston's Pixman
> renderer. I could bet Weston follows the GL convention of defining the
> extents of an image region to be the boundaries of the image, not the
> pixel centers which would leave a half pixel margin outside of the
> region. I mean, Weston works as if you are transforming geometric
> primitives like triangles, and rasterization happens later, while it
> still uses pixel centers at .5 coordinates, meaning that a single pixel
> covers the X-coordinates [0.0, 1.0).
> Are you saying that this idea doesn't work with Pixman?

I had a recollection of Pixman's geometric model, but given that there's
no documentation I felt the need to go back and check the source code, as
it can be very easy to get this sort of thing subtly wrong:

Pixman's scaling is such that pixel centres are similarly positioned
irrespective of whether you're doing nearest-neighbour or bilinear

For nearest-neighbour scaling, the nth pixel of a source or mask image is
considered to cover the space (n, n+1]. Yes, that's inclusive at the
upper end and exclusive at the lower end, not what you might expect (and
this is the reason for adjustments by pixman_fixed_e in various places).

For bilinear scaling, the contribution of the nth pixel scales up
linearly from 0 at n-0.5 to 1 at n+0.5 then back down to 0 at n+1.5, so
its overall range of influence is (n-0.5, n+1.5).

Since the centre coordinate of each destination pixel is what is fed
through the transformation matrix, you can see that under the identity
transform, there is always a 1:1 mapping from a single source pixel to a
single destination pixel, irrespective of whether you're nominally doing
nearest or bilinear scaling. This enables Pixman to select unscaled fast
paths just by examining the transform.

If you scale from the outer extents (in other words, use scale factors of
x/m, y/n rather than (x-1)/(m-1), (y-1)/(n-1), and align the top-left of
the first source pixel with the top-left of the first destination pixel)
then that's fine, as long as:

a) you're using nearest-neighbour scaling
b) you're using bilinear scaling and a scale factor > 1 (i.e. reduction
    rather than enlargement)

otherwise Pixman will decide that it needs to use a small contribution
 from a single-pixel border just outside the bounds of the source image,
for which it then needs to start following the repeat-type rules (pad/

> Hmm, sure, Pixman needs to transform pixel centers internally, since it
> rasterizes on the destination image... so what
> compute_transformed_extents() does is that it assumes the input is
> geometry, converts corner pixels into pixel centers for rasterization,
> and returns the bounding box of the transformed pixel centers.
> Then that is used to calculate what pixels would be accessed in the
> source image.
> Did I get that right?

Yes. Its only purpose is to determine the (inclusive) first and last
source pixels required, so that the caller can then check to see if they
are within bounds.

> Btw. are you sure there cannot be rounding in the hand-written fast
> paths? If some assembly path computes an approximation of source
> coordinates, could it not hit the "wrong" pixel? Zero coefficient or
> not.

I'm pretty sure, yes - at least for affine transforms. The transform
coefficients, inputs and outputs are all x.16 fixed point, with a rule
for handling rounding for the multiplications (round to nearest with
halfs rounding to +infinity) that's enforced in platform-neutral code
like pixman_transform_point_31_16(). As a fast path steps along a
destination row, there are no further multiplications, it just adds the
transform coefficients from the first column to the running total, and no
rounding is therefore needed.

If any fast path deviated from this, it would fail the test suite, which
requires binary-identical output. Actually, I wonder if this rounding
issue is the reason why projective transforms aren't more widely featured
in the tests?


More information about the Pixman mailing list