aboutsummaryrefslogtreecommitdiff
path: root/pixman
diff options
context:
space:
mode:
Diffstat (limited to 'pixman')
-rw-r--r--pixman/pixman/pixman-bits-image.c8
-rw-r--r--pixman/pixman/pixman-matrix.c10
-rw-r--r--pixman/pixman/rounding.txt134
-rw-r--r--pixman/test/affine-test.c6
-rw-r--r--pixman/test/rotate-test.c2
-rw-r--r--pixman/test/scaling-test.c6
6 files changed, 150 insertions, 16 deletions
diff --git a/pixman/pixman/pixman-bits-image.c b/pixman/pixman/pixman-bits-image.c
index 085dd1606..7787ef1b8 100644
--- a/pixman/pixman/pixman-bits-image.c
+++ b/pixman/pixman/pixman-bits-image.c
@@ -413,10 +413,10 @@ bits_image_fetch_pixel_convolution (bits_image_t *image,
}
}
- satot >>= 16;
- srtot >>= 16;
- sgtot >>= 16;
- sbtot >>= 16;
+ satot = (satot + 0x8000) >> 16;
+ srtot = (srtot + 0x8000) >> 16;
+ sgtot = (sgtot + 0x8000) >> 16;
+ sbtot = (sbtot + 0x8000) >> 16;
satot = CLIP (satot, 0, 0xff);
srtot = CLIP (srtot, 0, 0xff);
diff --git a/pixman/pixman/pixman-matrix.c b/pixman/pixman/pixman-matrix.c
index d2ab609dc..cd2f1b5b8 100644
--- a/pixman/pixman/pixman-matrix.c
+++ b/pixman/pixman/pixman-matrix.c
@@ -62,7 +62,7 @@ pixman_transform_point_3d (const struct pixman_transform *transform,
{
partial = ((pixman_fixed_48_16_t) transform->matrix[j][i] *
(pixman_fixed_48_16_t) vector->vector[i]);
- v += partial >> 16;
+ v += (partial + 0x8000) >> 16;
}
if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16)
@@ -96,16 +96,16 @@ pixman_transform_point (const struct pixman_transform *transform,
{
partial = ((pixman_fixed_32_32_t) transform->matrix[j][i] *
(pixman_fixed_32_32_t) vector->vector[i]);
- v[j] += partial >> 2;
+ v[j] += (partial + 2) >> 2;
}
}
- if (!(v[2] >> 16))
+ if (!((v[2] + 0x8000) >> 16))
return FALSE;
for (j = 0; j < 2; j++)
{
- quo = v[j] / (v[2] >> 16);
+ quo = v[j] / ((v[2] + 0x8000) >> 16);
if (quo > pixman_max_fixed_48_16 || quo < pixman_min_fixed_48_16)
return FALSE;
vector->vector[j] = (pixman_fixed_t) quo;
@@ -138,7 +138,7 @@ pixman_transform_multiply (struct pixman_transform * dst,
(pixman_fixed_32_32_t) l->matrix[dy][o] *
(pixman_fixed_32_32_t) r->matrix[o][dx];
- v += partial >> 16;
+ v += (partial + 0x8000) >> 16;
}
if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16)
diff --git a/pixman/pixman/rounding.txt b/pixman/pixman/rounding.txt
new file mode 100644
index 000000000..1a19f450f
--- /dev/null
+++ b/pixman/pixman/rounding.txt
@@ -0,0 +1,134 @@
+*** General notes about rounding
+
+Suppose a function is sampled at positions [k + o] where k is an
+integer and o is a fractional offset 0 <= o < 1.
+
+To round a value to the nearest sample, breaking ties by rounding up,
+we can do this:
+
+ round(x) = floor(x - o + 0.5) + o
+
+That is, first subtract o to let us pretend that the samples are at
+integer coordinates, then add 0.5 and floor to round to nearest
+integer, then add the offset back in.
+
+To break ties by rounding down:
+
+ round(x) = ceil(x - o - 0.5) + o
+
+or if we have an epsilon value:
+
+ round(x) = floor(x - o + 0.5 - e) + o
+
+To always round *up* to the next sample:
+
+ round_up(x) = ceil(x - o) + o
+
+To always round *down* to the previous sample:
+
+ round_down(x) = floor(x - o) + o
+
+If a set of samples is stored in an array, you get from the sample
+position to an index by subtracting the position of the first sample
+in the array:
+
+ index(s) = s - first_sample
+
+
+*** Application to pixman
+
+In pixman, images are sampled with o = 0.5, that is, pixels are
+located midways between integers. We usually break ties by rounding
+down (i.e., "round towards north-west").
+
+
+-- NEAREST filtering:
+
+The NEAREST filter simply picks the closest pixel to the given
+position:
+
+ round(x) = floor(x - 0.5 + 0.5 - e) + 0.5 = floor (x - e) + 0.5
+
+The first sample of a pixman image has position 0.5, so to find the
+index in the pixel array, we have to subtract 0.5:
+
+ floor (x - e) + 0.5 - 0.5 = floor (x - e).
+
+Therefore a 16.16 fixed-point image location is turned into a pixel
+value with NEAREST filtering by doing this:
+
+ pixels[((y - e) >> 16) * stride + ((x - e) >> 16)]
+
+where stride is the number of pixels allocated per scanline and e =
+0x0001.
+
+
+-- CONVOLUTION filtering:
+
+A convolution matrix is considered a sampling of a function f at
+values surrounding 0. For example, this convolution matrix:
+
+ [a, b, c, d]
+
+is interpreted as the values of a function f:
+
+ a = f(-1.5)
+ b = f(-0.5)
+ c = f(0.5)
+ d = f(1.5)
+
+The sample offset in this case is o = 0.5 and the first sample has
+position s0 = -1.5. If the matrix is:
+
+ [a, b, c, d, e]
+
+the sample offset is o = 0 and the first sample has position s0 =
+-2.0. In general we have
+
+ s0 = (- width / 2.0 + 0.5).
+
+and
+
+ o = frac (s0)
+
+To evaluate f at a position between the samples, we round to the
+closest sample, and then we subtract the position of the first sample
+to get the index in the matrix:
+
+ f(t) = matrix[floor(t - o + 0.5) + o - s0]
+
+Note that in this case we break ties by rounding up.
+
+If we write s0 = m + o, where m is an integer, this is equivalent to
+
+ f(t) = matrix[floor(t - o + 0.5) + o - (m + o)]
+ = matrix[floor(t - o + 0.5 - m) + o - o]
+ = matrix[floor(t - s0 + 0.5)]
+
+The convolution filter in pixman positions f such that 0 aligns with
+the given position x. For a given pixel x0 in the image, the closest
+sample of f is then computed by taking (x - x0) and rounding that to
+the closest index:
+
+ i = floor ((x0 - x) - s0 + 0.5)
+
+To perform the convolution, we have to find the first pixel x0 whose
+corresponding sample has index 0. We can write x0 = k + 0.5, where k
+is an integer:
+
+ 0 = floor(k + 0.5 - x - s0 + 0.5)
+
+ = k + floor(1 - x - s0)
+
+ = k - ceil(x + s0 - 1)
+
+ = k - floor(x + s0 - e)
+
+ = k - floor(x - (width - 1) / 2.0 - e)
+
+And so the final formula for the index k of x0 in the image is:
+
+ k = floor(x - (width - 1) / 2.0 - e)
+
+Computing the result is then simply a matter of convolving all the
+pixels starting at k with all the samples in the matrix.
diff --git a/pixman/test/affine-test.c b/pixman/test/affine-test.c
index 7bc28b4cd..daa86c81d 100644
--- a/pixman/test/affine-test.c
+++ b/pixman/test/affine-test.c
@@ -310,11 +310,11 @@ test_composite (int testnum,
}
#if BILINEAR_INTERPOLATION_BITS == 8
-#define CHECKSUM 0x1EF2175A
+#define CHECKSUM 0x344413F0
#elif BILINEAR_INTERPOLATION_BITS == 7
-#define CHECKSUM 0x74050F50
+#define CHECKSUM 0xC8181A76
#elif BILINEAR_INTERPOLATION_BITS == 4
-#define CHECKSUM 0x4362EAE8
+#define CHECKSUM 0xD672A457
#else
#define CHECKSUM 0x00000000
#endif
diff --git a/pixman/test/rotate-test.c b/pixman/test/rotate-test.c
index d63a28947..a0488ef22 100644
--- a/pixman/test/rotate-test.c
+++ b/pixman/test/rotate-test.c
@@ -108,6 +108,6 @@ int
main (int argc, const char *argv[])
{
return fuzzer_test_main ("rotate", 15000,
- 0x03A24D51,
+ 0x5236FD9F,
test_transform, argc, argv);
}
diff --git a/pixman/test/scaling-test.c b/pixman/test/scaling-test.c
index 273612395..035410333 100644
--- a/pixman/test/scaling-test.c
+++ b/pixman/test/scaling-test.c
@@ -380,11 +380,11 @@ test_composite (int testnum,
}
#if BILINEAR_INTERPOLATION_BITS == 8
-#define CHECKSUM 0x8D3A7539
+#define CHECKSUM 0x107B67ED
#elif BILINEAR_INTERPOLATION_BITS == 7
-#define CHECKSUM 0x03A23E0C
+#define CHECKSUM 0x30EC0CF0
#elif BILINEAR_INTERPOLATION_BITS == 4
-#define CHECKSUM 0xE96D1A5E
+#define CHECKSUM 0x87B496BC
#else
#define CHECKSUM 0x00000000
#endif