[Pixman] [PATCH v14 18/22] pixman-filter: Made Gaussian a bit wider

2016-03-06 Thread spitzak
From: Bill Spitzak 

Expanded the size slightly (from ~4.25 to 5) to make the cutoff less noticable.
Previouly the value at the cutoff was gaussian_filter(sqrt(2)*3/2) = 0.00626
which is larger than the difference between 8-bit pixels (1/255 = 0.003921).
New cutoff is gaussian_filter(2.5) = 0.001089 which is smaller.

v11: added some math to commit message
v14: left SIGMA in there
Signed-off-by: Bill Spitzak 
Acked-by: Oded Gabbay 
---
 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 4b7..f582187 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -143,7 +143,7 @@ static const filter_info_t filters[] =
 { PIXMAN_KERNEL_BOX,   box_kernel,   1.0 },
 { PIXMAN_KERNEL_LINEAR,linear_kernel,2.0 },
 { PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 },
-{ PIXMAN_KERNEL_GAUSSIAN,  gaussian_kernel,  6 * SIGMA },
+{ PIXMAN_KERNEL_GAUSSIAN,  gaussian_kernel,  5.0 },
 { PIXMAN_KERNEL_LANCZOS2,  lanczos2_kernel,  4.0 },
 { PIXMAN_KERNEL_LANCZOS3,  lanczos3_kernel,  6.0 },
 { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel,  8.0 },
-- 
1.9.1

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


[Pixman] [PATCH v14 07/22] pixman-filter: reduce amount of malloc/free/memcpy to generate filter

2016-03-06 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.

v8: small refactor to remove the filter_width function

v10: Restored filter_width function but with arguments changed to
 match later patches

v11: Removed unused arg and pointer from filter_width function
 Whitespace fixes.

Signed-off-by: Bill Spitzak 
Reviewed-by: Oded Gabbay 
---
 pixman/pixman-filter.c | 57 --
 1 file changed, 23 insertions(+), 34 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index d6c0f74..a29116a 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -217,25 +217,17 @@ integral (pixman_kernel_t kernel1, double x1,
 }
 }
 
-static pixman_fixed_t *
-create_1d_filter (int *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 +242,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 +271,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 +283,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;
 }
 
 #ifdef PIXMAN_GNUPLOT
@@ -338,6 +328,12 @@ gnuplot_filter (int width, int samples, const 
pixman_fixed_t* p)
 }
 #endif
 
+static int
+filter_width (pixman_kernel_t reconstruct, pixman_kernel_t sample, double size)
+{
+return ceil (filters[reconstruct].width + size * filters[sample].width);
+}
+
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
  * with the given kernels and scale parameters
  */
@@ -354,42 +350,35 @@ 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;
 
+width = filter_width (reconstruct_x, sample_x, sx);
 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);
+height = filter_width (reconstruct_y, sample_y, sy);
+subsample_y = (1 << subsample_bits_y);
 
-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));
+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);
 
 #ifdef PIXMAN_GNUPLOT
 gnuplot_filter(width, subsample_x, params+4);
 #endif
 
-out:
-free (horz);
-free (vert);
-
 return params;
 }
-- 
1.9.1

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


[Pixman] [PATCH v14 04/22] demos/scale: fix blank subsamples spin box

2016-03-06 Thread spitzak
From: Bill Spitzak 

It now shows the initial value of 4 when the demo is started

Signed-off-by: Bill Spitzak 
---
 demos/scale.ui | 1 +
 1 file changed, 1 insertion(+)

diff --git a/demos/scale.ui b/demos/scale.ui
index b62cbfb..6028ab7 100644
--- a/demos/scale.ui
+++ b/demos/scale.ui
@@ -321,6 +321,7 @@
   
 True
subsample_adjustment
+   4
   
   
 1
-- 
1.9.1

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


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

2016-03-06 Thread spitzak
From: Bill Spitzak 

This is very useful for comparing the results of SEPARABLE_CONVOLUTION
with BILINEAR and NEAREST.

v14: Removed good/best items

Signed-off-by: Bill Spitzak 
---
 demos/scale.c  | 12 +++-
 demos/scale.ui | 40 ++--
 2 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/demos/scale.c b/demos/scale.c
index 0995ad0..85c12e4 100644
--- a/demos/scale.c
+++ b/demos/scale.c
@@ -127,6 +127,13 @@ 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 },
+};
+
 static const named_int_t filters[] =
 {
 { "Box",   PIXMAN_KERNEL_BOX },
@@ -260,7 +267,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"));
@@ -402,6 +411,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
   
 
 
@@ -304,7 +324,7 @@
  

[Pixman] [PATCH v14 14/22] pixman-filter: Do BOX.BOX much faster

2016-03-06 Thread spitzak
From: Bill Spitzak 

The desired result from the integration is directly available, as the range has 
been
clipped to the intersection of the two boxes. As this filter is probably the 
most
common one, this optimization looks very useful.

Signed-off-by: Bill Spitzak 
---
 pixman/pixman-filter.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 6d589c2..8dfb49b 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -171,6 +171,11 @@ integral (pixman_kernel_t kernel1,
 {
return filters[kernel2].func (-pos * scale) * scale;
 }
+else if (kernel1 == PIXMAN_KERNEL_BOX && kernel2 == PIXMAN_KERNEL_BOX)
+{
+   assert (high <= low + 1.0);
+   return (high - low) * scale;
+}
 /* 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
-- 
1.9.1

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


[Pixman] [PATCH v14 22/22] demos/scale: Add good/best filter types

2016-03-06 Thread spitzak
From: Bill Spitzak 

Allows testing them. Good is the default to match default behavior of
pixman/cairo at startup.

v14: Locked axis put in it's own commit

Signed-off-by: Bill Spitzak 
---
 demos/scale.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/demos/scale.c b/demos/scale.c
index 0c6b533..d1fce5d 100644
--- a/demos/scale.c
+++ b/demos/scale.c
@@ -132,6 +132,8 @@ 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[] =
@@ -338,7 +340,7 @@ on_expose (GtkWidget *da, GdkEvent *event, gpointer data)
 
 static void
 set_up_combo_box (app_t *app, const char *box_name,
-  int n_entries, const named_int_t table[])
+  int n_entries, const named_int_t table[], int active)
 {
 GtkWidget *widget = get_widget (app, box_name);
 GtkListStore *model;
@@ -364,7 +366,7 @@ set_up_combo_box (app_t *app, const char *box_name,
gtk_list_store_set (model, , 0, info->name, -1);
 }
 
-gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
 
 g_signal_connect (widget, "changed", G_CALLBACK (rescale), app);
 }
@@ -372,7 +374,7 @@ set_up_combo_box (app_t *app, const char *box_name,
 static void
 set_up_filter_box (app_t *app, const char *box_name)
 {
-set_up_combo_box (app, box_name, G_N_ELEMENTS (filters), filters);
+set_up_combo_box (app, box_name, G_N_ELEMENTS (filters), filters, 0);
 }
 
 static char *
@@ -420,14 +422,14 @@ 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_combo_box (app, "filter_combo_box", G_N_ELEMENTS (filter_types), 
filter_types, 3);
 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");
 set_up_filter_box (app, "sample_y_combo_box");
 
 set_up_combo_box (
-app, "repeat_combo_box", G_N_ELEMENTS (repeats), repeats);
+   app, "repeat_combo_box", G_N_ELEMENTS (repeats), repeats, 0);
 
 g_signal_connect (
gtk_builder_get_object (app->builder, "lock_checkbutton"),
-- 
1.9.1

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


[Pixman] [PATCH v14 06/22] pixman-image: Added enable-gnuplot config to view filters in gnuplot

2016-03-06 Thread spitzak
From: Bill Spitzak 

If enable-gnuplot is configured, then you can pipe the output of a pixman-using 
program
to gnuplot and get a continuously-updated plot of the horizontal filter. This
works well with demos/scale to test the filter generation.

The plot is all the different subposition filters shuffled together. This is
misleading in a few cases:

  IMPULSE.BOX - goes up and down as the subfilters have different numbers of 
non-zero samples
  IMPULSE.TRIANGLE - somewhat crooked for the same reason
  1-wide filters - looks triangular, but a 1-wide box would be more accurate

v7: First time this ability was included

v8: Use config option
Moved code to the filter generator
Modified scale demo to not call filter generator a second time.

v10: Only print if successful generation of plots
 Use #ifdef, not #if

v11: small whitespace fixes

Signed-off-by: Bill Spitzak 
Reviewed-by: Oded Gabbay 
---
 configure.ac   | 13 +
 pixman/pixman-filter.c | 45 +
 2 files changed, 58 insertions(+)

diff --git a/configure.ac b/configure.ac
index 6b2134e..e833e45 100644
--- a/configure.ac
+++ b/configure.ac
@@ -834,6 +834,19 @@ fi
 AC_SUBST(PIXMAN_TIMERS)
 
 dnl ===
+dnl gnuplot
+
+AC_ARG_ENABLE(gnuplot,
+   [AC_HELP_STRING([--enable-gnuplot],
+   [enable output of filters that can be piped to gnuplot 
[default=no]])],
+   [enable_gnuplot=$enableval], [enable_gnuplot=no])
+
+if test $enable_gnuplot = yes ; then
+   AC_DEFINE(PIXMAN_GNUPLOT, 1, [enable output that can be piped to gnuplot])
+fi
+AC_SUBST(PIXMAN_GNUPLOT)
+
+dnl ===
 dnl GTK+
 
 AC_ARG_ENABLE(gtk,
diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index b2bf53f..d6c0f74 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -297,6 +297,47 @@ create_1d_filter (int *width,
 return params;
 }
 
+#ifdef PIXMAN_GNUPLOT
+/* If enable-gnuplot is configured, then you can pipe the output of a
+ * pixman-using program to gnuplot and get a continuously-updated plot
+ * of the horizontal filter. This works well with demos/scale to test
+ * the filter generation.
+ *
+ * The plot is all the different subposition filters shuffled
+ * together. This is misleading in a few cases:
+ *
+ *  IMPULSE.BOX - goes up and down as the subfilters have different
+ *   numbers of non-zero samples
+ *  IMPULSE.TRIANGLE - somewhat crooked for the same reason
+ *  1-wide filters - looks triangular, but a 1-wide box would be more
+ *  accurate
+ */
+static void
+gnuplot_filter (int width, int samples, const pixman_fixed_t* p)
+{
+int x,y;
+printf ("plot '-' with linespoints\n");
+printf ("%g 0\n", - width * .5);
+for (x = 0; x < width; ++x) {
+   for (y = 0; y < samples; ++y) {
+   int yy;
+   if (width & 1)
+   yy = y;
+   else if (y >= samples / 2)
+   yy = y - samples / 2;
+   else
+   yy = samples / 2 + y;
+   printf ("%g %g\n",
+   x - width * 0.5 + (y + 0.5) * (1.0 / samples),
+   pixman_fixed_to_double(p[(yy + 1) * width - x - 1]));
+   }
+}
+printf ("%g 0\n", width * .5);
+printf ("e\n");
+fflush (stdout);
+}
+#endif
+
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
  * with the given kernels and scale parameters
  */
@@ -342,6 +383,10 @@ pixman_filter_create_separable_convolution (int
 *n_values,
 memcpy (params + 4 + width * subsample_x, vert,
height * subsample_y * sizeof (pixman_fixed_t));
 
+#ifdef PIXMAN_GNUPLOT
+gnuplot_filter(width, subsample_x, params+4);
+#endif
+
 out:
 free (horz);
 free (vert);
-- 
1.9.1

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


[Pixman] [PATCH v14 09/22] pixman-filter: Correct Simpsons integration

2016-03-06 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,0,6,0,6...,2,1.

With this fix the integration is accurate enough that the number of samples
could be reduced a lot. Multiples of 12 seem to work best.

v7: Merged with patch to reduce from 128 samples to 16
v9: Changed samples from 16 to 12
v10: Fixed rebase error that made it not compile
v11: minor whitespace change
v14: more whitespace changes

Signed-off-by: Bill Spitzak 
Reviewed-by: Oded Gabbay 
---
 pixman/pixman-filter.c | 21 +++--
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index c03a7f6..bd5ac4c 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -189,13 +189,19 @@ integral (pixman_kernel_t kernel1, double x1,
 }
 else
 {
-   /* Integration via Simpson's rule */
-#define N_SEGMENTS 128
+   /* Integration via Simpson's rule
+* See http://www.intmath.com/integration/6-simpsons-rule.php
+* 12 segments (6 cubic approximations) seems to produce best
+* result for lanczos3.linear, which was the combination that
+* showed the most errors.  This makes sense as the lanczos3
+* filter is 6 wide.
+*/
+#define N_SEGMENTS 12
 #define SAMPLE(a1, a2) \
(filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))

double s = 0.0;
-   double h = width / (double)N_SEGMENTS;
+   double h = width / N_SEGMENTS;
int i;
 
s = SAMPLE (x1, x2);
@@ -204,11 +210,14 @@ integral (pixman_kernel_t kernel1, double x1,
{
double a1 = x1 + h * i;
double a2 = x2 + h * i;
+   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);
-
-   if (i >= 2 && i < N_SEGMENTS - 1)
-   s += 4 * SAMPLE (a1, a2);
}
 
s += SAMPLE (x1 + width, x2 + width);
-- 
1.9.1

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


[Pixman] [PATCH v14 10/22] pixman-filter: Correct integration with impulse filters

2016-03-06 Thread spitzak
From: Bill Spitzak 

The IMPULSE special-cases did not sample the center of the of the region. This
caused it to sample the filters outside their range, and produce assymetric
filters and other errors. Fixing this required changing the arguments to
integral() so the correct point could be determined.

Signed-off-by: Bill Spitzak 
---
 pixman/pixman-filter.c | 111 ++---
 1 file changed, 49 insertions(+), 62 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index bd5ac4c..fef2189 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -147,45 +147,46 @@ 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
- * and integrates the product of the kernels across @width.
+/* This function scales @kernel2 by @scale, shifts it by @pos,
+ * and then integrates the product of the kernels across low..high
  *
  * This function assumes that the intervals are within
  * the kernels in question. E.g., the caller must not
  * 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,
- double width)
+integral (pixman_kernel_t kernel1,
+ pixman_kernel_t kernel2, double scale, double pos,
+ double low, double high)
 {
+if (high < low)
+{
+   return 0.0;
+}
+else if (kernel2 == PIXMAN_KERNEL_IMPULSE)
+{
+   return filters[kernel1].func (-pos);
+}
+else if (kernel1 == PIXMAN_KERNEL_IMPULSE)
+{
+   return filters[kernel2].func (-pos * scale);
+}
 /* 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 (low < 0 && high > 0)
 {
return
-   integral (kernel1, x1, kernel2, scale, x2, - x1) +
-   integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1);
+   integral (kernel1, kernel2, scale, pos, low, 0) +
+   integral (kernel1, kernel2, scale, pos, 0, high);
 }
-else if (x2 < 0 && x2 + width > 0)
+else if (low < pos && high > pos)
 {
return
-   integral (kernel1, x1, kernel2, scale, x2, - x2) +
-   integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2);
-}
-else if (kernel1 == PIXMAN_KERNEL_IMPULSE)
-{
-   assert (width == 0.0);
-   return filters[kernel2].func (x2 * scale);
-}
-else if (kernel2 == PIXMAN_KERNEL_IMPULSE)
-{
-   assert (width == 0.0);
-   return filters[kernel1].func (x1);
+   integral (kernel1, kernel2, scale, pos, low, pos) +
+   integral (kernel1, kernel2, scale, pos, pos, high);
 }
 else
 {
@@ -197,30 +198,28 @@ integral (pixman_kernel_t kernel1, double x1,
 * filter is 6 wide.
 */
 #define N_SEGMENTS 12
-#define SAMPLE(a1, a2) \
-   (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))
-   
+#define SAMPLE(a)  \
+   (filters[kernel1].func ((a)) * filters[kernel2].func (((a) - pos)))
+
double s = 0.0;
-   double h = width / N_SEGMENTS;
+   double h = (high - low) / N_SEGMENTS;
int i;
 
-   s = SAMPLE (x1, x2);
+   s = SAMPLE (low);
 
for (i = 1; i < N_SEGMENTS; i += 2)
{
-   double a1 = x1 + h * i;
-   double a2 = x2 + h * i;
-   s += 4 * SAMPLE (a1, a2);
+   double a1 = low + h * i;
+   s += 4 * SAMPLE (a1);
}
 
for (i = 2; i < N_SEGMENTS; i += 2)
{
-   double a1 = x1 + h * i;
-   double a2 = x2 + h * i;
-   s += 2 * SAMPLE (a1, a2);
+   double a1 = low + h * i;
+   s += 2 * SAMPLE (a1);
}
 
-   s += SAMPLE (x1 + width, x2 + width);
+   s += SAMPLE (high);

return h * s * (1.0 / 3.0);
 }
@@ -235,55 +234,43 @@ create_1d_filter (int  width,
  pixman_fixed_t *p)
 {
 double step;
+double rwidth2 = filters[reconstruct].width / 2.0;
+double swidth2 = size * filters[sample].width / 2.0;
 int i;
 
 step = 1.0 / n_phases;
 
 for (i = 0; i < n_phases; ++i)
 {
-double frac = step / 2.0 + i * step;
+   double frac = step / 2.0 + i * step;
pixman_fixed_t new_total;
-int x, x1, x2;
-   double total;
+   int x;
+   double pos, total;
 
/* Sample convolution of reconstruction and sampling
 * filter. See rounding.txt regarding the rounding
 * and sample 

[Pixman] [PATCH v14 17/22] pixman-filter: Nested polynomial for cubic

2016-03-06 Thread spitzak
From: Bill Spitzak 

v11: Restored range checks

Signed-off-by: Bill Spitzak 
Reviewed-by: Oded Gabbay 
---
 pixman/pixman-filter.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index ab62e0a..4b7 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -109,14 +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;
+   return (((12 - 9 * B - 6 * C) * ax +
+(-18 + 12 * B + 6 * C)) * ax * ax +
+   (6 - 2 * B)) / 6;
 }
-else if (ax >= 1 && ax < 2)
+else if (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 -B - 6 * C) * ax +
+ (6 * B + 30 * C)) * ax +
+(-12 * B - 48 * C)) * ax +
+   (8 * B + 24 * C)) / 6;
 }
 else
 {
-- 
1.9.1

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


[Pixman] [PATCH v14 20/22] pixman-image: Detect all 8 transforms that can do nearest filter

2016-03-06 Thread spitzak
From: Bill Spitzak 

This patch consolidates the examination of the matrix into one place, and 
detects
the reflected versions of the transforms that can be done with nearest filter.

v14: Split this code from the GOOD/BEST as I think it will be accepted.

Signed-off-by: Bill Spitzak 
---
 pixman/pixman-image.c | 119 --
 1 file changed, 57 insertions(+), 62 deletions(-)

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 1ff1a49..8ad2891 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -266,52 +266,82 @@ compute_image_info (pixman_image_t *image)
 {
 pixman_format_code_t code;
 uint32_t flags = 0;
+int nearest_ok = FALSE;
+pixman_fixed_t (*m)[3];
 
 /* Transform */
 if (!image->common.transform)
 {
+   nearest_ok = TRUE;
flags |= (FAST_PATH_ID_TRANSFORM|
  FAST_PATH_X_UNIT_POSITIVE |
  FAST_PATH_Y_UNIT_ZERO |
  FAST_PATH_AFFINE_TRANSFORM);
+   m = 0;
 }
 else
 {
+   m = image->common.transform->matrix;
+
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)
+   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;
+   /* no scaling */
+   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];
+   /* x/y axis are swapped, 90 degree rotation */
+   if (abs(m[0][1]) == pixman_fixed_1 &&
+   abs(m[1][0]) == pixman_fixed_1)
+   {
+   /* no scaling */
+   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 (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 (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]) > pixman_int_to_fixed (3) ||
+abs(m[1][2]) > pixman_int_to_fixed (3))
+   nearest_ok = FALSE;
}
}
 
-   if (image->common.transform->matrix[0][0] > 0)
+   if (m[0][0] > 0)
flags |= FAST_PATH_X_UNIT_POSITIVE;
 
-   if (image->common.transform->matrix[1][0] == 0)
+   if (m[1][0] == 0)
flags |= FAST_PATH_Y_UNIT_ZERO;
 }
 
@@ -326,48 +356,10 @@ compute_image_info (pixman_image_t *image)
 case PIXMAN_FILTER_BILINEAR:
 case PIXMAN_FILTER_GOOD:
 case PIXMAN_FILTER_BEST:
-   flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
-
-  

[Pixman] [PATCH v14 13/22] pixman-filter: integral splitting is only needed for triangle filter

2016-03-06 Thread spitzak
From: Bill Spitzak 

Only the triangle is discontinuous at 0. The other filters resemble a cubic 
closely
enough that Simpsons integration works without splitting.

Signed-off-by: Bill Spitzak 
---
 pixman/pixman-filter.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index f9ad45f..6d589c2 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -176,13 +176,13 @@ integral (pixman_kernel_t kernel1,
  * as LINEAR that are not differentiable at 0 will still
  * integrate properly.
  */
-else if (low < 0 && high > 0)
+else if (kernel1 == PIXMAN_KERNEL_LINEAR && low < 0 && high > 0)
 {
return
integral (kernel1, kernel2, scale, pos, low, 0) +
integral (kernel1, kernel2, scale, pos, 0, high);
 }
-else if (low < pos && high > pos)
+else if (kernel2 == PIXMAN_KERNEL_LINEAR && low < pos && high > pos)
 {
return
integral (kernel1, kernel2, scale, pos, low, pos) +
-- 
1.9.1

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


[Pixman] [PATCH v14 08/22] pixman-filter: rename "scale" to "size" when it is 1/scale

2016-03-06 Thread spitzak
From: Bill Spitzak 

This is to remove some confusion when reading the code. "scale" gets larger
as the picture gets larger, while "size" (ie the size of the filter) gets
smaller.

v14: Removed changes to integral function

Signed-off-by: Bill Spitzak 
Reviewed-by: Oded Gabbay 
---
 pixman/pixman-filter.c | 18 +-
 pixman/pixman.h|  6 +++---
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index a29116a..c03a7f6 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -221,7 +221,7 @@ static void
 create_1d_filter (int  width,
  pixman_kernel_t  reconstruct,
  pixman_kernel_t  sample,
- double   scale,
+ double   size,
  int  n_phases,
  pixman_fixed_t *p)
 {
@@ -251,8 +251,8 @@ create_1d_filter (int  width,
double pos = x + 0.5 - frac;
double rlow = - filters[reconstruct].width / 2.0;
double rhigh = rlow + filters[reconstruct].width;
-   double slow = pos - scale * filters[sample].width / 2.0;
-   double shigh = slow + scale * filters[sample].width;
+   double slow = pos - size * filters[sample].width / 2.0;
+   double shigh = slow + size * filters[sample].width;
double c = 0.0;
double ilow, ihigh;
 
@@ -262,7 +262,7 @@ create_1d_filter (int  width,
ihigh = MIN (shigh, rhigh);
 
c = integral (reconstruct, ilow,
- sample, 1.0 / scale, ilow - pos,
+ sample, 1.0 / size, ilow - pos,
  ihigh - ilow);
}
 
@@ -335,12 +335,12 @@ filter_width (pixman_kernel_t reconstruct, 
pixman_kernel_t sample, double size)
 }
 
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
- * with the given kernels and scale parameters
+ * with the given kernels and size parameters
  */
 PIXMAN_EXPORT pixman_fixed_t *
 pixman_filter_create_separable_convolution (int *n_values,
-   pixman_fixed_t   scale_x,
-   pixman_fixed_t   scale_y,
+   pixman_fixed_t   size_x,
+   pixman_fixed_t   size_y,
pixman_kernel_t  reconstruct_x,
pixman_kernel_t  reconstruct_y,
pixman_kernel_t  sample_x,
@@ -348,8 +348,8 @@ pixman_filter_create_separable_convolution (int 
*n_values,
int  subsample_bits_x,
int  subsample_bits_y)
 {
-double sx = fabs (pixman_fixed_to_double (scale_x));
-double sy = fabs (pixman_fixed_to_double (scale_y));
+double sx = fabs (pixman_fixed_to_double (size_x));
+double sy = fabs (pixman_fixed_to_double (size_y));
 pixman_fixed_t *params;
 int subsample_x, subsample_y;
 int width, height;
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 509ba5e..b012a33 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -845,12 +845,12 @@ typedef enum
 } pixman_kernel_t;
 
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
- * with the given kernels and scale parameters.
+ * with the given kernels and size parameters.
  */
 pixman_fixed_t *
 pixman_filter_create_separable_convolution (int *n_values,
-   pixman_fixed_t   scale_x,
-   pixman_fixed_t   scale_y,
+   pixman_fixed_t   size_x,
+   pixman_fixed_t   size_y,
pixman_kernel_t  reconstruct_x,
pixman_kernel_t  reconstruct_y,
pixman_kernel_t  sample_x,
-- 
1.9.1

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


[Pixman] [PATCH v14 16/22] pixman-filter: distribute normalization error over filter

2016-03-06 Thread spitzak
From: Bill Spitzak 

This removes a high-frequency spike in the middle of some filters that is
caused by math errors all being in the same direction.

Signed-off-by: Bill Spitzak 
---
 pixman/pixman-filter.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 36dd811..ab62e0a 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -282,8 +282,18 @@ create_1d_filter (int  width,
p[x] = t;
}
 
+   /* Distribute any remaining error over all samples */
if (new_total != pixman_fixed_1)
-   p[width / 2] += (pixman_fixed_1 - new_total);
+   {
+   pixman_fixed_t delta = new_total - pixman_fixed_1;
+   pixman_fixed_t t = 0;
+   for (x = 0; x < width; ++x)
+   {
+   pixman_fixed_t new_t = delta * (x + 1) / width;
+   p[x] += new_t - t;
+   t = new_t;
+   }
+   }
 
p += width;
 }
-- 
1.9.1

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


[Pixman] [PATCH v14] Implement PIXMAN_FILTER_GOOD/BEST

2016-03-06 Thread spitzak
Changes from previous version:

* The actual change to filtering separated from other changes that I think
  have more chance at being accepted.
* Changes to integral function split into mulitple commits
* Whitespace fixes
* Good/best patch has fix for bug noticed by Søren

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


[Pixman] [PATCH v14 12/22] pixman-filter: fix subsample_bits == 0

2016-03-06 Thread spitzak
From: Bill Spitzak 

The position of only one subsample was wrong as ceil() was done on an integer.
Use a different function for all odd numbers of subsamples that gets this right.

Signed-off-by: Bill Spitzak 
---
 pixman/pixman-filter.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index ac89dda..f9ad45f 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -252,7 +252,10 @@ create_1d_filter (int  width,
 * and sample positions.
 */
 
-   pos = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac;
+   if (n_phases & 1)
+   pos = frac - width / 2.0;
+   else
+   pos = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac;
 
total = 0;
for (x = 0; x < width; ++x, ++pos)
-- 
1.9.1

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