[Pixman] [PATCH 05/15] pixman-filter: Correct Simpsons integration

2015-12-12 Thread spitzak
From: Bill Spitzak 

Simpsons uses cubic curve fitting, with 3 samples defining each cubic. This
makes the weights of the samples be in a pattern of 1,4,2,4,2...4,1, and then
dividing the result by 3.

The previous code was using weights of 1,2,6,6...6,2,1 which produced about 2x
the correct value, as it was still dividing by 3. The filter normalization
removed this error. Also this is effectively a linear interpolation except for
the ends.
---
 pixman/pixman-filter.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 15f9069..7c1da0d 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -204,11 +204,14 @@ integral (pixman_kernel_t reconstruct, double x1,
{
double a1 = x1 + h * i;
double a2 = x2 + h * i;
+   s += 4 * SAMPLE(a1, a2);
+   }
 
-   s += 2 * SAMPLE (a1, a2);
-
-   if (i >= 2 && i < N_SEGMENTS - 1)
-   s += 4 * SAMPLE (a1, a2);
+   for (i = 2; i < N_SEGMENTS; i += 2)
+   {
+   double a1 = x1 + h * i;
+   double a2 = x2 + h * i;
+   s += 2 * SAMPLE(a1, a2);
}
 
s += SAMPLE (x1 + width, x2 + width);
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 02/15] demos/scale: Added pulldown to choose PIXMAN_FILTER_* value

2015-12-12 Thread spitzak
From: Bill Spitzak 

This allows testing of GOOD/BEST and to do comparisons between
the basic filters and PIXMAN_FILTER_SEPARABLE_CONVOLUTION settings.
---
 demos/scale.c  | 14 +-
 demos/scale.ui | 40 ++--
 2 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/demos/scale.c b/demos/scale.c
index 71c7791..203168f 100644
--- a/demos/scale.c
+++ b/demos/scale.c
@@ -68,6 +68,15 @@ typedef struct
 intvalue;
 } named_int_t;
 
+static const named_int_t filter_types[] =
+{
+{ "Separable", PIXMAN_FILTER_SEPARABLE_CONVOLUTION },
+{ "Nearest",   PIXMAN_FILTER_NEAREST },
+{ "Bilinear",  PIXMAN_FILTER_BILINEAR },
+{ "Good",  PIXMAN_FILTER_GOOD },
+{ "Best",  PIXMAN_FILTER_BEST },
+};
+
 static const named_int_t filters[] =
 {
 { "Box",   PIXMAN_KERNEL_BOX },
@@ -201,7 +210,9 @@ rescale (GtkWidget *may_be_null, app_t *app)
gtk_adjustment_get_value (app->subsample_adjustment),
gtk_adjustment_get_value (app->subsample_adjustment));
 
-pixman_image_set_filter (app->original, 
PIXMAN_FILTER_SEPARABLE_CONVOLUTION, params, n_params);
+pixman_image_set_filter (app->original,
+   get_value (app, filter_types, "filter_combo_box"),
+   params, n_params);
 
 pixman_image_set_repeat (
 app->original, get_value (app, repeats, "repeat_combo_box"));
@@ -343,6 +354,7 @@ app_new (pixman_image_t *original)
 widget = get_widget (app, "drawing_area");
 g_signal_connect (widget, "expose_event", G_CALLBACK (on_expose), app);
 
+set_up_combo_box (app, "filter_combo_box", G_N_ELEMENTS (filter_types), 
filter_types);
 set_up_filter_box (app, "reconstruct_x_combo_box");
 set_up_filter_box (app, "reconstruct_y_combo_box");
 set_up_filter_box (app, "sample_x_combo_box");
diff --git a/demos/scale.ui b/demos/scale.ui
index ee985dd..b62cbfb 100644
--- a/demos/scale.ui
+++ b/demos/scale.ui
@@ -191,12 +191,23 @@
 8
 6
 
+  
+True
+1
+bFilter:/b
+True
+  
+
+
   
 True
 1
 bReconstruct X:/b
 True
   
+  
+1
+  
 
 
   
@@ -206,7 +217,7 @@
 True
   
   
-1
+2
   
 
 
@@ -217,7 +228,7 @@
 True
   
   
-2
+3
   
 
 
@@ -228,7 +239,7 @@
 True
   
   
-3
+4
   
 
 
@@ -239,7 +250,7 @@
 True
   
   
-4
+5
   
 
 
@@ -250,7 +261,15 @@
 True
   
   
-5
+6
+  
+
+
+  
+True
+  
+  
+1
   
 
 
@@ -259,6 +278,7 @@
   
   
 1
+1
   
 
 
@@ -267,7 +287,7 @@
   
   
 1
-1
+2
   
 
 
@@ -276,7 +296,7 @@
   
   
 1
-2
+3
   
 
 
@@ -285,7 +305,7 @@
   
   
 1
-3
+4
   
 
 
@@ -294,7 +314,7 @@
   
   
 1
-4
+5
   

[Pixman] [PATCH 06/15] pixman-filter: reduced number of samples in Simpson's integration

2015-12-12 Thread spitzak
From: Bill Spitzak 

With the cubic fix this is plenty accurate enough, far in excess of the pixman
fixed-point error limit. Likely even 16 samples is too many.
---
 pixman/pixman-filter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 7c1da0d..4aafa51 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -190,7 +190,7 @@ integral (pixman_kernel_t reconstruct, double x1,
 else
 {
/* Integration via Simpson's rule */
-#define N_SEGMENTS 128
+#define N_SEGMENTS 16
 #define SAMPLE(a1, a2) \
(filters[reconstruct].func ((a1)) * filters[sample].func ((a2) / scale))

-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 03/15] pixman-filter: Consistency in arg names to integral ()

2015-12-12 Thread spitzak
From: Bill Spitzak 

Rename kernel1/2 to reconstruct/sample and use 1/scale as the
scale argument, thus matching the names in other functions.
---
 pixman/pixman-filter.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index b2bf53f..05bc345 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -147,8 +147,8 @@ static const filter_info_t filters[] =
 { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel,  8.0 },
 };
 
-/* This function scales @kernel2 by @scale, then
- * aligns @x1 in @kernel1 with @x2 in @kernel2 and
+/* This function scales @sample by @scale, then
+ * aligns @x1 in @reconstruct with @x2 in @sample and
  * and integrates the product of the kernels across @width.
  *
  * This function assumes that the intervals are within
@@ -156,8 +156,8 @@ static const filter_info_t filters[] =
  * try to integrate a linear kernel ouside of [-1:1]
  */
 static double
-integral (pixman_kernel_t kernel1, double x1,
- pixman_kernel_t kernel2, double scale, double x2,
+integral (pixman_kernel_t reconstruct, double x1,
+ pixman_kernel_t sample, double scale, double x2,
  double width)
 {
 /* If the integration interval crosses zero, break it into
@@ -168,31 +168,31 @@ integral (pixman_kernel_t kernel1, double x1,
 if (x1 < 0 && x1 + width > 0)
 {
return
-   integral (kernel1, x1, kernel2, scale, x2, - x1) +
-   integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1);
+   integral (reconstruct, x1, sample, scale, x2, - x1) +
+   integral (reconstruct, 0, sample, scale, x2 - x1, width + x1);
 }
 else if (x2 < 0 && x2 + width > 0)
 {
return
-   integral (kernel1, x1, kernel2, scale, x2, - x2) +
-   integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2);
+   integral (reconstruct, x1, sample, scale, x2, - x2) +
+   integral (reconstruct, x1 - x2, sample, scale, 0, width + x2);
 }
-else if (kernel1 == PIXMAN_KERNEL_IMPULSE)
+else if (reconstruct == PIXMAN_KERNEL_IMPULSE)
 {
assert (width == 0.0);
-   return filters[kernel2].func (x2 * scale);
+   return filters[sample].func (x2 / scale);
 }
-else if (kernel2 == PIXMAN_KERNEL_IMPULSE)
+else if (sample == PIXMAN_KERNEL_IMPULSE)
 {
assert (width == 0.0);
-   return filters[kernel1].func (x1);
+   return filters[reconstruct].func (x1);
 }
 else
 {
/* Integration via Simpson's rule */
 #define N_SEGMENTS 128
 #define SAMPLE(a1, a2) \
-   (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))
+   (filters[reconstruct].func ((a1)) * filters[sample].func ((a2) / scale))

double s = 0.0;
double h = width / (double)N_SEGMENTS;
@@ -270,7 +270,7 @@ create_1d_filter (int *width,
ihigh = MIN (shigh, rhigh);
 
c = integral (reconstruct, ilow,
- sample, 1.0 / scale, ilow - pos,
+ sample, scale, ilow - pos,
  ihigh - ilow);
}
 
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 04/15] pixman-filter: reduce amount of malloc/free/memcpy to generate filter

2015-12-12 Thread spitzak
From: Bill Spitzak 

Rearranged so that the entire block of memory for the filter pair
is allocated first, and then filled in. Previous version allocated
and freed two temporary buffers for each filter and did an extra
memcpy.
---
 pixman/pixman-filter.c | 59 +-
 1 file changed, 25 insertions(+), 34 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 05bc345..15f9069 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -217,25 +217,25 @@ integral (pixman_kernel_t reconstruct, double x1,
 }
 }
 
-static pixman_fixed_t *
-create_1d_filter (int *width,
+static int
+filter_width (pixman_kernel_t reconstruct,
+ pixman_kernel_t sample,
+ double scale)
+{
+return ceil (scale * filters[sample].width + filters[reconstruct].width);
+}
+
+static void
+create_1d_filter (int  width,
  pixman_kernel_t  reconstruct,
  pixman_kernel_t  sample,
  double   scale,
- int  n_phases)
+ int  n_phases,
+ pixman_fixed_t *p)
 {
-pixman_fixed_t *params, *p;
 double step;
-double size;
 int i;
 
-size = scale * filters[sample].width + filters[reconstruct].width;
-*width = ceil (size);
-
-p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t));
-if (!params)
-return NULL;
-
 step = 1.0 / n_phases;
 
 for (i = 0; i < n_phases; ++i)
@@ -250,8 +250,8 @@ create_1d_filter (int *width,
 * and sample positions.
 */
 
-   x1 = ceil (frac - *width / 2.0 - 0.5);
-x2 = x1 + *width;
+   x1 = ceil (frac - width / 2.0 - 0.5);
+x2 = x1 + width;
 
total = 0;
 for (x = x1; x < x2; ++x)
@@ -279,7 +279,7 @@ create_1d_filter (int *width,
 }
 
/* Normalize */
-   p -= *width;
+   p -= width;
 total = 1 / total;
 new_total = 0;
for (x = x1; x < x2; ++x)
@@ -291,10 +291,8 @@ create_1d_filter (int *width,
}
 
if (new_total != pixman_fixed_1)
-   *(p - *width / 2) += (pixman_fixed_1 - new_total);
+   *(p - width / 2) += (pixman_fixed_1 - new_total);
 }
-
-return params;
 }
 
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
@@ -313,38 +311,31 @@ pixman_filter_create_separable_convolution (int   
  *n_values,
 {
 double sx = fabs (pixman_fixed_to_double (scale_x));
 double sy = fabs (pixman_fixed_to_double (scale_y));
-pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL;
+pixman_fixed_t *params;
 int subsample_x, subsample_y;
 int width, height;
 
 subsample_x = (1 << subsample_bits_x);
 subsample_y = (1 << subsample_bits_y);
 
-horz = create_1d_filter (, reconstruct_x, sample_x, sx, subsample_x);
-vert = create_1d_filter (, reconstruct_y, sample_y, sy, 
subsample_y);
+width = filter_width (reconstruct_x, sample_x, sx);
+height = filter_width (reconstruct_y, sample_y, sy);
 
-if (!horz || !vert)
-goto out;
-
 *n_values = 4 + width * subsample_x + height * subsample_y;
-
+
 params = malloc (*n_values * sizeof (pixman_fixed_t));
 if (!params)
-goto out;
+return NULL;
 
 params[0] = pixman_int_to_fixed (width);
 params[1] = pixman_int_to_fixed (height);
 params[2] = pixman_int_to_fixed (subsample_bits_x);
 params[3] = pixman_int_to_fixed (subsample_bits_y);
 
-memcpy (params + 4, horz,
-   width * subsample_x * sizeof (pixman_fixed_t));
-memcpy (params + 4 + width * subsample_x, vert,
-   height * subsample_y * sizeof (pixman_fixed_t));
-
-out:
-free (horz);
-free (vert);
+create_1d_filter (width, reconstruct_x, sample_x, sx, subsample_x,
+ params + 4);
+create_1d_filter (height, reconstruct_y, sample_y, sy, subsample_y,
+ params + 4 + width * subsample_x);
 
 return params;
 }
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 13/15] pixman-filter: refactor cubic polynominal and don't range check

2015-12-12 Thread spitzak
From: Bill Spitzak 

The other filters do not check for x being in range, so there is
no reason for cubic to do so.
---
 pixman/pixman-filter.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 7e10108..bf9dce3 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -109,18 +109,16 @@ general_cubic (double x, double B, double C)
 
 if (ax < 1)
 {
-   return ((12 - 9 * B - 6 * C) * ax * ax * ax +
-   (-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6;
-}
-else if (ax >= 1 && ax < 2)
-{
-   return ((-B - 6 * C) * ax * ax * ax +
-   (6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) *
-   ax + (8 * B + 24 * C)) / 6;
+   return (((12 - 9 * B - 6 * C) * ax +
+(-18 + 12 * B + 6 * C)) * ax * ax +
+   (6 - 2 * B)) / 6;
 }
 else
 {
-   return 0;
+   return -B - 6 * C) * ax +
+(6 * B + 30 * C)) * ax +
+   (-12 * B - 48 * C)) * ax +
+   (8 * B + 24 * C)) / 6;
 }
 }
 
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 12/15] pixman-filter: Turn off subsampling when not necessary

2015-12-12 Thread spitzak
From: Bill Spitzak 

If sample is IMPULSE and reconstruct is BOX or IMPULSE the sub-pixel
position of the sample is not relevant, so only one subsample is needed.
---
 pixman/pixman-filter.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 64981cd..7e10108 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -230,6 +230,8 @@ filter_width (pixman_kernel_t reconstruct,
  pixman_kernel_t sample,
  double scale)
 {
+if (reconstruct == PIXMAN_KERNEL_BOX && sample == PIXMAN_KERNEL_IMPULSE)
+   return 0;
 return ceil (scale * filters[sample].width + filters[reconstruct].width);
 }
 
@@ -323,13 +325,13 @@ pixman_filter_create_separable_convolution (int   
  *n_values,
 int subsample_x, subsample_y;
 int width, height;
 
-subsample_x = (1 << subsample_bits_x);
-subsample_y = (1 << subsample_bits_y);
-
 width = filter_width (reconstruct_x, sample_x, sx);
-if (width < 1) width = 1;
+if (width < 1) { width = 1; subsample_bits_x = 0; }
 height = filter_width (reconstruct_y, sample_y, sy);
-if (height < 1) height = 1;
+if (height < 1) { height = 1; subsample_bits_y = 0; }
+
+subsample_x = (1 << subsample_bits_x);
+subsample_y = (1 << subsample_bits_y);
 
 *n_values = 4 + width * subsample_x + height * subsample_y;
 
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 11/15] pixman-filter: made IMPULSE.IMPULSE not produce a zero-wide filter

2015-12-12 Thread spitzak
From: Bill Spitzak 

With the other patch to put error on the center pixel, this produces
the same result as BOX.IMPULSE filter.
---
 pixman/pixman-filter.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 00126cd..64981cd 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -327,7 +327,9 @@ pixman_filter_create_separable_convolution (int 
*n_values,
 subsample_y = (1 << subsample_bits_y);
 
 width = filter_width (reconstruct_x, sample_x, sx);
+if (width < 1) width = 1;
 height = filter_width (reconstruct_y, sample_y, sy);
+if (height < 1) height = 1;
 
 *n_values = 4 + width * subsample_x + height * subsample_y;
 
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 09/15] pixman-filter: put filter error on center pixel

2015-12-12 Thread spitzak
From: Bill Spitzak 

Any error in filter normalization is placed on the center of odd-sized filters,
rather than 1 pixel to the right.

In particular this fixes the 1-wide filters produced by impulse sampling
so they are 1.0 rather than 0.0.
---
 pixman/pixman-filter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 0cd4a68..fbc657d 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -299,7 +299,7 @@ create_1d_filter (int  width,
}
 
if (new_total != pixman_fixed_1)
-   *(p - width / 2) += (pixman_fixed_1 - new_total);
+   *(p - (width + 1) / 2) += (pixman_fixed_1 - new_total);
 }
 }
 
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 07/15] pixman-filter: Speed up the BOX+BOX filter

2015-12-12 Thread spitzak
From: Bill Spitzak 

This is easy as the caller already intersected the two boxes, so
the width is the integral.
---
 pixman/pixman-filter.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 4aafa51..782f73d 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -182,6 +182,11 @@ integral (pixman_kernel_t reconstruct, double x1,
assert (width == 0.0);
return filters[sample].func (x2 / scale);
 }
+else if (reconstruct == PIXMAN_KERNEL_BOX && sample == PIXMAN_KERNEL_BOX)
+{
+   assert (width <= 1.0);
+   return width;
+}
 else if (sample == PIXMAN_KERNEL_IMPULSE)
 {
assert (width == 0.0);
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 08/15] pixman-filter: Don't recurse unnecessarily.

2015-12-12 Thread spitzak
From: Bill Spitzak 

Only LINEAR is not differentiable at zero, so only do the recursive
split of the integral for it.
---
 pixman/pixman-filter.c | 34 +-
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 782f73d..0cd4a68 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -160,38 +160,38 @@ integral (pixman_kernel_t reconstruct, double x1,
  pixman_kernel_t sample, double scale, double x2,
  double width)
 {
+if (reconstruct == PIXMAN_KERNEL_IMPULSE)
+{
+   assert (width == 0.0);
+   return filters[sample].func (x2 / scale);
+}
+else if (reconstruct == PIXMAN_KERNEL_BOX && sample == PIXMAN_KERNEL_BOX)
+{
+   assert (width <= 1.0);
+   return width;
+}
+else if (sample == PIXMAN_KERNEL_IMPULSE)
+{
+   assert (width == 0.0);
+   return filters[reconstruct].func (x1);
+}
 /* If the integration interval crosses zero, break it into
  * two separate integrals. This ensures that filters such
  * as LINEAR that are not differentiable at 0 will still
  * integrate properly.
  */
-if (x1 < 0 && x1 + width > 0)
+else if (reconstruct == PIXMAN_KERNEL_LINEAR && x1 < 0 && x1 + width > 0)
 {
return
integral (reconstruct, x1, sample, scale, x2, - x1) +
integral (reconstruct, 0, sample, scale, x2 - x1, width + x1);
 }
-else if (x2 < 0 && x2 + width > 0)
+else if (sample == PIXMAN_KERNEL_LINEAR && x2 < 0 && x2 + width > 0)
 {
return
integral (reconstruct, x1, sample, scale, x2, - x2) +
integral (reconstruct, x1 - x2, sample, scale, 0, width + x2);
 }
-else if (reconstruct == PIXMAN_KERNEL_IMPULSE)
-{
-   assert (width == 0.0);
-   return filters[sample].func (x2 / scale);
-}
-else if (reconstruct == PIXMAN_KERNEL_BOX && sample == PIXMAN_KERNEL_BOX)
-{
-   assert (width <= 1.0);
-   return width;
-}
-else if (sample == PIXMAN_KERNEL_IMPULSE)
-{
-   assert (width == 0.0);
-   return filters[reconstruct].func (x1);
-}
 else
 {
/* Integration via Simpson's rule */
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 15/15] pixman-image: Implement PIXMAN_FILTER_GOOD/BEST as separable convolutions

2015-12-12 Thread spitzak
From: Bill Spitzak 

Detects and uses PIXMAN_FILTER_NEAREST for all 8 90-degree rotations and
reflections when the scale is 1.0 and integer translation.

GOOD uses:

 scale < 1/16 : BOX.BOX at size 16
 scale < 3/4 : BOX.BOX at size 1/scale
 larger : BOX.BOX at size 1

 If both directions have a scale >= 3/4 or a scale of 1/2 and an integer
 translation, the faster PIXMAN_FILTER_BILINEAR code is used.

BEST uses:

 scale < 1/24 : BOX.BOX at size 24
 scale < 1/16 : BOX.BOX at size 1/scale
 scale < 1 : IMPULSE.LANCZOS2 at size 1/scale
 scale < 2 : IMPULSE.LANCZOS2 at size 1
 scale < 128 : BOX.LANCZOS2 at size 1/(scale-1) (antialiased square pixels)
 larger : BOX.LANCZOS2 at size 1/127 (antialias blur gets thicker)
---
 pixman/pixman-image.c | 298 +-
 1 file changed, 219 insertions(+), 79 deletions(-)

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 1ff1a49..f7d74a1 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "pixman-private.h"
 
@@ -274,112 +275,251 @@ compute_image_info (pixman_image_t *image)
  FAST_PATH_X_UNIT_POSITIVE |
  FAST_PATH_Y_UNIT_ZERO |
  FAST_PATH_AFFINE_TRANSFORM);
+   switch (image->common.filter)
+   {
+   case PIXMAN_FILTER_CONVOLUTION:
+   break;
+   case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
+   flags |= FAST_PATH_SEPARABLE_CONVOLUTION_FILTER;
+   break;
+   default:
+   flags |= (FAST_PATH_NEAREST_FILTER | 
FAST_PATH_NO_CONVOLUTION_FILTER);
+   break;
+   }
 }
 else
 {
+   pixman_fixed_t (*m)[3] = image->common.transform->matrix;
+   double dx, dy;
+   int xsubsample, ysubsample;
+   int nearest_ok, bilinear_ok;
+
flags |= FAST_PATH_HAS_TRANSFORM;
 
-   if (image->common.transform->matrix[2][0] == 0  &&
-   image->common.transform->matrix[2][1] == 0  &&
-   image->common.transform->matrix[2][2] == pixman_fixed_1)
+   nearest_ok = FALSE;
+bilinear_ok = FALSE;
+
+   if (m[2][0] == 0&&
+   m[2][1] == 0&&
+   m[2][2] == pixman_fixed_1)
{
flags |= FAST_PATH_AFFINE_TRANSFORM;
 
-   if (image->common.transform->matrix[0][1] == 0 &&
-   image->common.transform->matrix[1][0] == 0)
+   if (m[0][1] == 0 && m[1][0] == 0)
{
-   if (image->common.transform->matrix[0][0] == -pixman_fixed_1 &&
-   image->common.transform->matrix[1][1] == -pixman_fixed_1)
+   flags |= FAST_PATH_SCALE_TRANSFORM;
+   if (abs(m[0][0]) == pixman_fixed_1 &&
+   abs(m[1][1]) == pixman_fixed_1)
{
-   flags |= FAST_PATH_ROTATE_180_TRANSFORM;
+   nearest_ok = TRUE;
+   if (m[0][0] < 0 && m[1][1] < 0)
+   flags |= FAST_PATH_ROTATE_180_TRANSFORM;
}
-   flags |= FAST_PATH_SCALE_TRANSFORM;
}
-   else if (image->common.transform->matrix[0][0] == 0 &&
-image->common.transform->matrix[1][1] == 0)
+   else if (m[0][0] == 0 && m[1][1] == 0)
{
-   pixman_fixed_t m01 = image->common.transform->matrix[0][1];
-   pixman_fixed_t m10 = image->common.transform->matrix[1][0];
-
-   if (m01 == -pixman_fixed_1 && m10 == pixman_fixed_1)
-   flags |= FAST_PATH_ROTATE_90_TRANSFORM;
-   else if (m01 == pixman_fixed_1 && m10 == -pixman_fixed_1)
-   flags |= FAST_PATH_ROTATE_270_TRANSFORM;
+   if (abs(m[0][1]) == pixman_fixed_1 &&
+   abs(m[1][0]) == pixman_fixed_1)
+   {
+   nearest_ok = TRUE;
+   if (m[0][1] < 0 && m[1][0] > 0)
+   flags |= FAST_PATH_ROTATE_90_TRANSFORM;
+   else if (m[0][1] > 0 && m[1][0] < 0)
+   flags |= FAST_PATH_ROTATE_270_TRANSFORM;
+   }
}
}
 
-   if (image->common.transform->matrix[0][0] > 0)
+   if (nearest_ok)
+   {
+   /* reject non-integer translation: */
+   if (pixman_fixed_frac (m[0][2] | m[1][2]))
+   nearest_ok = FALSE;
+   /* FIXME: there are some affine-test failures, showing
+* that handling of BILINEAR and NEAREST filter is not
+* quite equivalent when getting close to 32K for the
+* translation components of the matrix. That's likely
+* some bug, but for now just skip BILINEAR->NEAREST
+* optimization in this case.
+*/
+   else if (abs(m[0][2] | m[1][2]) > pixman_int_to_fixed (3))
+   

[Pixman] [PATCH 01/15] demos/scale: Compute filter size using boundary of xformed ellipse, not rectangle

2015-12-12 Thread spitzak
From: Bill Spitzak 

This is much more accurate and less blurry. In particular the filtering does
not change as the image is rotated.
---
 demos/scale.c | 43 ++-
 1 file changed, 2 insertions(+), 41 deletions(-)

diff --git a/demos/scale.c b/demos/scale.c
index d00307e..71c7791 100644
--- a/demos/scale.c
+++ b/demos/scale.c
@@ -55,50 +55,11 @@ get_widget (app_t *app, const char *name)
 return widget;
 }
 
-static double
-min4 (double a, double b, double c, double d)
-{
-double m1, m2;
-
-m1 = MIN (a, b);
-m2 = MIN (c, d);
-return MIN (m1, m2);
-}
-
-static double
-max4 (double a, double b, double c, double d)
-{
-double m1, m2;
-
-m1 = MAX (a, b);
-m2 = MAX (c, d);
-return MAX (m1, m2);
-}
-
 static void
 compute_extents (pixman_f_transform_t *trans, double *sx, double *sy)
 {
-double min_x, max_x, min_y, max_y;
-pixman_f_vector_t v[4] =
-{
-   { { 1, 1, 1 } },
-   { { -1, 1, 1 } },
-   { { -1, -1, 1 } },
-   { { 1, -1, 1 } },
-};
-
-pixman_f_transform_point (trans, [0]);
-pixman_f_transform_point (trans, [1]);
-pixman_f_transform_point (trans, [2]);
-pixman_f_transform_point (trans, [3]);
-
-min_x = min4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]);
-max_x = max4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]);
-min_y = min4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]);
-max_y = max4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]);
-
-*sx = (max_x - min_x) / 2.0;
-*sy = (max_y - min_y) / 2.0;
+*sx = hypot (trans->m[0][0], trans->m[0][1]) / trans->m[2][2];
+*sy = hypot (trans->m[1][0], trans->m[1][1]) / trans->m[2][2];
 }
 
 typedef struct
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH pixman] V6 implement PIXMAN_FILTER_GOOD/BEST

2015-12-12 Thread spitzak
This is identical to my previous series of patches except rebased atop the
current git master. Note that all patches except the last one are bug fixes
to produce correct filters, and do not produce any changes in pixman output.
IMHO the first 14 patches should be applied asap.

The last patch changes the output when GOOD or BEST filters are used and 
images are scaled down. Output is nearly identical to what cairo is 
producing now, but I did some minor tweaks to cutoffs between filters 
and handling of very small scales. This one also detects a few more 
instances where nearest or bilinear can be used as a fast path.

With all of these applied, the filter generation can be removed from cairo as
pixman will do it. The fallback to image for the X11 backend could be removed
if it is known the X11 server is using this new version.

This is also a necessary step in order to introduce 2-pass image filtering
to pixman. Currently software such as Cairo cannot use the filtering in
pixman and this means it will bypass any such improvements.

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


[Pixman] [PATCH 10/15] pixman-filter: don't range-check impulse filter

2015-12-12 Thread spitzak
From: Bill Spitzak 

The other filters don't range-check, so there is no need for this
one to either. It is only called with x==0.
---
 pixman/pixman-filter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index fbc657d..00126cd 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -45,7 +45,7 @@ typedef struct
 static double
 impulse_kernel (double x)
 {
-return (x == 0.0)? 1.0 : 0.0;
+return 1;
 }
 
 static double
-- 
1.9.1

___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


Re: [Pixman] Plan to release final development version before stable branch

2015-12-12 Thread Bill Spitzak
On Fri, Dec 11, 2015 at 4:15 AM, Oded Gabbay  wrote:

> On Thu, Dec 10, 2015 at 11:19 PM, Bill Spitzak  wrote:
> > Can you include my patches to fix the filtering? They have been posted
> for a
> > long time now.
> >
> > The last patch makes GOOD/BEST use filtering for scaling images down.
> This
> > matches the current Cairo behavior and would allow Cairo to use the
> pixman
> > backend rather than doing an image fallback for any image scaling smaller
> > than .75. It also contains a bunch of minor optimizaion and filter
> selection
> > tweaks that makes the output somewhat better than current Cairo.
> >
> Hi Bill,
>
> Unfortunately, I don't see anyone reviewed your patches, and from what
> I heard, those are quite significant changes.
>
> It's a shame you didn't bring this up when I did the first development
> release 4 months ago. Then we had enough time to check and test it.
> I'm quite hesitant of including such changes right before the final
> development version, even with a review.
>

I did send email on May 22, 2015, in response to your comments.

I suggest that you try to contact one of pixman's veterans (Soren,
> Siarhei, Matt, Pekka, Ben) offline and ask them nicely to at least
> skim over the patches and give a high-level opinion about the series.
>

These were discussed with Soren before. He disagreed with my previous
version because I changed to a single filter calculation rather than his
pair of filters being convoluted. This version preserves the pair of
filters, with some fixes of bugs that caused artifacts in the resulting
filters. I'm sending email directly in case they are not reading the pixman
list.

>
> Also, check if you need to rebase the patches against current pixman
> and if so, maybe send the series again. It might stir up a discussion.
>

The patches applied to the newest version without any conflicts and my test
programs still work. I have resent them to the pixman mailing list.

>
> I'm willing to review them in terms of correctness and code style, but
> I'm not veteran enough in pixman to give an opinion on the underlying
> changes (which is the most important issue).
>

Anything would be great.

I believe these work well and have been using them for a while. This would
allow the removal of redundant code in Cairo, and would allow 2-pass
filtering to be done at some point in the future, which would really
improve pixman performance.
___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman