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

Ben Avison bavison at riscosopen.org
Thu Apr 23 09:12:59 PDT 2015


On Thu, 23 Apr 2015 12:46:56 +0100,
Pekka Paalanen <ppaalanen at gmail.com> wrote:

> On Wed, 15 Apr 2015 17:03:43 +0100
> "Ben Avison" <bavison at riscosopen.org> wrote:
>
>> 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).
>
> Aha. Slightly surprising. Is this only internal to Pixman, or does it
> show outside too? That is, something that users should take into
> account, needed for the "exact alignment" to hit the COVER_CLIP?

I've never been really sure if it was intended to work that way, but it's
the way the code functions as written. If you change it, you do hit some
subtle differences in the test suite, but I wonder if it's doing what the
author intended. I say that because with most "obvious" scaling factors,
assuming you don't use a translation in the transform matrix (i.e. you
scale from pixel edges) then you don't actually hit the borderline
position very often, if ever, so it's strange that they went to any
effort to do anything other than what works out to be the simplest thing
to do.

I think some ASCII art might help. Consider a 4x enlargement.

Key:
| integer X in source space
- integer Y in source space
S centre of source pixel (half-integer X and Y)
D point at which source is sampled (centre of destination pixel)

   +---------------+---------------+
   | D   D   D   D | D   D   D   D |
   |               |               |
   | D   D   D   D | D   D   D   D |
   |       S       |       S       |
   | D   D   D   D | D   D   D   D |
   |               |               |
   | D   D   D   D | D   D   D   D |
   +---------------+---------------+
   | D   D   D   D | D   D   D   D |
   |               |               |
   | D   D   D   D | D   D   D   D |
   |       S       |       S       |
   | D   D   D   D | D   D   D   D |
   |               |               |
   | D   D   D   D | D   D   D   D |
   +---------------+---------------+

You can see that we never actually sample any of the boundary lines, so
the adjustment by pixman_fixed_e has no effect in this case. The same is
true of any integer enlargement factor, at least until you start to get
close to 65536x enlargement.

If you're cunning, you might ask about half-integer enlargement factors.
Here's what a 2.5x enlargement looks like:

   +-------------------+-------------------+
   |                   |                   |
   |   D       D       D       D       D   |
   |                   |                   |
   |                   |                   |
   |         S         |         S         |
   |   D       D       D       D       D   |
   |                   |                   |
   |                   |                   |
   |                   |                   |
   +---D-------D-------D-------D-------D---+
   |                   |                   |
   |                   |                   |
   |                   |                   |
   |   D       D       D       D       D   |
   |         S         |         S         |
   |                   |                   |
   |                   |                   |
   |   D       D       D       D       D   |
   |                   |                   |
   +-------------------+-------------------+

But this neglects the fact that this requires a value of 2/5 in the
transform matrix. This, like the reciprocals of all other half-integer
values (2/3, 2/7, 2/9, 2/11 etc) are subject to rounding error when
represented as binary, so you won't actually end up hitting the
borderline regularly.

The only case I can think of where you would routinely sample at the
edges is for a power-of-two reduction. For example, this is what a 0.25
scale factor looks like:

   +---+---+---+---+---+---+---+---+
   | S | S | S | S | S | S | S | S |
   +---+---+---+---+---+---+---+---+
   | S | S | S | S | S | S | S | S |
   +---+---D---+---+---+---D---+---+
   | S | S | S | S | S | S | S | S |
   +---+---+---+---+---+---+---+---+
   | S | S | S | S | S | S | S | S |
   +---+---+---+---+---+---+---+---+
   | S | S | S | S | S | S | S | S |
   +---+---+---+---+---+---+---+---+
   | S | S | S | S | S | S | S | S |
   +---+---D---+---+---+---D---+---+
   | S | S | S | S | S | S | S | S |
   +---+---+---+---+---+---+---+---+
   | S | S | S | S | S | S | S | S |
   +---+---+---+---+---+---+---+---+

The (n, n+1] rule means that you would sample the 2nd and 6th source
pixels, rather than the 3rd and 7th if you used a [n, n+1) rule.

If I had to hazard a guess, I'd say that the authors were looking solely
at the 0.5 scale factor case and were surprised to find they got the 2nd,
4th, 6th source pixels out rather than the 1st, 3rd, 5th and added the
pixman_fixed_e to "correct" this rather than looking at the wider
picture. But that's just a guess.

The balance seems to shift the other way if you scale from pixel centres
rather than edges, and it becomes easier to hit the edges with
enlargements rather than reductions. Here's what a 4x enlargement looks
like when destination pixels are centred on source pixels:

   S   D   D   D   S   D   D   D   S
           |               |
   D   D   D   D   D   D   D   D   D
           |               |
   D---D---D---D---D---D---D---D---D
           |               |
   D   D   D   D   D   D   D   D   D
           |               |
   S   D   D   D   S   D   D   D   S
           |               |
   D   D   D   D   D   D   D   D   D
           |               |
   D---D---D---D---D---D---D---D---D
           |               |
   D   D   D   D   D   D   D   D   D
           |               |
   S   D   D   D   S   D   D   D   S

The source pixels would be represented in a 3:4:2 ratio at the
destination, as opposed to 2:4:3.

> I'm guessing yes, because you do that in affine-bench, reversed... am I
> on the right track here?

Affine-bench only uses integer translation offsets, and it only uses any
at all to ensure it's only testing the COVER_CLIP case. This means it's
effectively testing the scale-from-pixel-edges model, and if you aren't
testing reflection, rotation or anything else that involve negative
transform coefficients, and you weren't testing bilinear scaling, then
you could get away with passing src_x and src_y = 0 to bench().

You may be getting a bit confused by the fact that when calculating xmin
etc in main() that I unconditionally half a pixel extra space. Normally
this is only relevant for bilinear scaling, but a source image that
satisfies COVER_CLIP for bilinear scaling will always satisfy COVER_CLIP
for nearest scaling too, and I wasn't too concerned with allocating one
pixel too many here and there.

> Ok, yeah. Since Weston is working with geometry rather than pixels, I
> think that works just fine... except for the left or top edge, which
> like you said for the pixel occupancy rules, would be accounted to an
> outside pixel. Sounds like should be removing pixman_fixed_e in Weston
> from the source area left and top or something to hit COVER_CLIP.

Remember, affine-bench is doing things kind of backwards compared to what
most use cases would be. It has a fixed size destination buffer and has
been told to use a particular affine transform, and it's trying to work
backwards to find out how large a source image it needs to start from to
be able to achieve this without having to invoke source image repeat.

I imagine most of the time, you'll have a source image of fixed size, and
you'll either have a target destination size (in which case your task is
to calculate the transform matrix coefficients) or you'll have a target
scaling factor (in which case your task is to work out the destination
size that can be achieved without running off the sides of the source
image).

Ben


More information about the Pixman mailing list