Re: [Pixman] [PATCH v9 03/15] pixman-image: Added enable-gnuplot config to view filters in gnuplot
On Mon, Feb 1, 2016 at 4:10 PM, Oded Gabbaywrote: > On Fri, Jan 22, 2016 at 11:42 AM, wrote: >> 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 >> >> v8: Use config option >> Moved code to the filter generator >> Modified scale demo to not call filter generator a second time. >> >> v7: First time this ability was included One more thing. The vX comments should be ordered from first to last (old to new), so: v7: ... v8: ... Oded >> >> Signed-off-by: Bill Spitzak >> --- >> configure.ac | 13 + >> demos/scale.c | 29 +++-- >> pixman/pixman-filter.c | 45 + >> 3 files changed, 77 insertions(+), 10 deletions(-) >> >> diff --git a/configure.ac b/configure.ac >> index 6b2134e..8066cb2 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/demos/scale.c b/demos/scale.c >> index 06821e3..881004e 100644 >> --- a/demos/scale.c >> +++ b/demos/scale.c >> @@ -258,16 +258,25 @@ rescale (GtkWidget *may_be_null, app_t *app) >> pixman_transform_from_pixman_f_transform (, ); >> pixman_image_set_transform (app->original, ); >> >> -params = pixman_filter_create_separable_convolution ( >> -_params, >> -sx * 65536.0 + 0.5, >> - sy * 65536.0 + 0.5, >> - get_value (app, filters, "reconstruct_x_combo_box"), >> - get_value (app, filters, "reconstruct_y_combo_box"), >> - get_value (app, filters, "sample_x_combo_box"), >> - get_value (app, filters, "sample_y_combo_box"), >> - gtk_adjustment_get_value (app->subsample_adjustment), >> - gtk_adjustment_get_value (app->subsample_adjustment)); >> +if (get_value (app, filter_types, "filter_combo_box") == >> + PIXMAN_FILTER_SEPARABLE_CONVOLUTION) >> +{ >> + params = pixman_filter_create_separable_convolution ( >> +_params, >> + sx * 65536.0 + 0.5, >> + sy * 65536.0 + 0.5, >> + get_value (app, filters, "reconstruct_x_combo_box"), >> + get_value (app, filters, "reconstruct_y_combo_box"), >> + get_value (app, filters, "sample_x_combo_box"), >> + get_value (app, filters, "sample_y_combo_box"), >> + gtk_adjustment_get_value (app->subsample_adjustment), >> + gtk_adjustment_get_value (app->subsample_adjustment)); >> +} >> +else >> +{ >> + params = 0; >> + n_params = 0; >> +} > > Wait, what the above code has to do with this patch ? > It wasn't in the previous version (v7) and I don't see how it is > related to the gnuplot. > This seems like a fix to the demo code. > If what I said is correct, please split it into a different patch. > >> >> pixman_image_set_filter (app->original, >> get_value (app, filter_types, "filter_combo_box"), >> diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c >> index b2bf53f..fe0d261 100644 >> --- a/pixman/pixman-filter.c >> +++ b/pixman/pixman-filter.c >> @@ -297,6 +297,47 @@ create_1d_filter (int *width, >> return params; >> } >> >> +#if PIXMAN_GNUPLOT > > To keep consistency with other defines checks, please use #ifdef when > checking just one define > >> +/* 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 >> + *
Re: [Pixman] [PATCH v9 02/15] demos/scale: Added pulldown to choose PIXMAN_FILTER_* value
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > From: Bill Spitzak > > This allows testing of GOOD/BEST and to do comparisons between > the basic filters and PIXMAN_FILTER_SEPARABLE_CONVOLUTION settings. > > Signed-off-by: Bill Spitzak > --- > 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 0995ad0..06821e3 100644 > --- a/demos/scale.c > +++ b/demos/scale.c > @@ -127,6 +127,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 }, > @@ -260,7 +269,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 +413,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 > + translatable="yes">bFilter:/b > +True > + > + > + > > True > 1 > translatable="yes">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 >
Re: [Pixman] [PATCH v9 03/15] pixman-image: Added enable-gnuplot config to view filters in gnuplot
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > 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 > > v8: Use config option > Moved code to the filter generator > Modified scale demo to not call filter generator a second time. > > v7: First time this ability was included > > Signed-off-by: Bill Spitzak > --- > configure.ac | 13 + > demos/scale.c | 29 +++-- > pixman/pixman-filter.c | 45 + > 3 files changed, 77 insertions(+), 10 deletions(-) > > diff --git a/configure.ac b/configure.ac > index 6b2134e..8066cb2 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/demos/scale.c b/demos/scale.c > index 06821e3..881004e 100644 > --- a/demos/scale.c > +++ b/demos/scale.c > @@ -258,16 +258,25 @@ rescale (GtkWidget *may_be_null, app_t *app) > pixman_transform_from_pixman_f_transform (, ); > pixman_image_set_transform (app->original, ); > > -params = pixman_filter_create_separable_convolution ( > -_params, > -sx * 65536.0 + 0.5, > - sy * 65536.0 + 0.5, > - get_value (app, filters, "reconstruct_x_combo_box"), > - get_value (app, filters, "reconstruct_y_combo_box"), > - get_value (app, filters, "sample_x_combo_box"), > - get_value (app, filters, "sample_y_combo_box"), > - gtk_adjustment_get_value (app->subsample_adjustment), > - gtk_adjustment_get_value (app->subsample_adjustment)); > +if (get_value (app, filter_types, "filter_combo_box") == > + PIXMAN_FILTER_SEPARABLE_CONVOLUTION) > +{ > + params = pixman_filter_create_separable_convolution ( > +_params, > + sx * 65536.0 + 0.5, > + sy * 65536.0 + 0.5, > + get_value (app, filters, "reconstruct_x_combo_box"), > + get_value (app, filters, "reconstruct_y_combo_box"), > + get_value (app, filters, "sample_x_combo_box"), > + get_value (app, filters, "sample_y_combo_box"), > + gtk_adjustment_get_value (app->subsample_adjustment), > + gtk_adjustment_get_value (app->subsample_adjustment)); > +} > +else > +{ > + params = 0; > + n_params = 0; > +} Wait, what the above code has to do with this patch ? It wasn't in the previous version (v7) and I don't see how it is related to the gnuplot. This seems like a fix to the demo code. If what I said is correct, please split it into a different patch. > > pixman_image_set_filter (app->original, > get_value (app, filter_types, "filter_combo_box"), > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > index b2bf53f..fe0d261 100644 > --- a/pixman/pixman-filter.c > +++ b/pixman/pixman-filter.c > @@ -297,6 +297,47 @@ create_1d_filter (int *width, > return params; > } > > +#if PIXMAN_GNUPLOT To keep consistency with other defines checks, please use #ifdef when checking just one define > +/* 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"); > +
Re: [Pixman] [PATCH v9 06/15] pixman-filter: Correct Simpsons integration
DOH! You are right, I should make sure each step compiles. I am also very much tempted to change "scale" to "size" to avoid the fact that the value is approximately the reciprocal of what must users would call the "scale" of the transform. That will require testing each patch. On Mon, Feb 1, 2016 at 6:34 AM, Oded Gabbaywrote: > On Fri, Jan 22, 2016 at 11:42 AM, wrote: > > 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. Since it divided > by > > 3 this produced about 2x the desired value (the normalization fixed > this). > > Also this is effectively a linear interpolation, not Simpsons > integration. > > > > 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. > > > > v9: Changed samples from 16 to 12 > > v7: Merged with patch to reduce from 128 samples to 16 > > > > Signed-off-by: Bill Spitzak > > --- > > pixman/pixman-filter.c | 29 +++-- > > 1 file changed, 19 insertions(+), 10 deletions(-) > > > > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > > index 55073c4..718649a 100644 > > --- a/pixman/pixman-filter.c > > +++ b/pixman/pixman-filter.c > > @@ -189,13 +189,19 @@ integral (pixman_kernel_t reconstruct, double x1, > > } > > else > > { > > - /* Integration via Simpson's rule */ > > -#define N_SEGMENTS 128 > > -#define SAMPLE(a1, a2) \ > > - (filters[reconstruct].func ((a1)) * filters[sample].func ((a2) / > scale)) > > - > > + /* 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(a) \ > > + (filters[reconstruct].func ((a)) * filters[sample].func (((a) - > pos) / scale)) > > + > You changed the SAMPLE macro to get 1 parameter, but in all the calls > you send 2 parameters, which make the compilation fail. > > Please fix this and resend the patch. > > Oded > > > 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 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 mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 06/15] pixman-filter: reduce amount of malloc/free/memcpy to generate filter
From: Bill SpitzakRearranged 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 Signed-off-by: Bill Spitzak Reviewed-by: Oded Gabbay --- pixman/pixman-filter.c | 59 ++ 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index acfb110..6c077b6 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -217,23 +217,17 @@ integral (pixman_kernel_t reconstruct, 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 size, - int n_phases) + int n_phases, + pixman_fixed_t *p) { -pixman_fixed_t *params, *p; double step; int i; -*width = ceil (size * filters[sample].width + filters[reconstruct].width); - -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) @@ -248,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) @@ -277,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) @@ -289,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 @@ -336,6 +328,14 @@ gnuplot_filter(int width, int samples, const pixman_fixed_t* p) } #endif +/* Besides calculating the width, this can modify the scale and subsample_bits */ +static int +filter_width(pixman_kernel_t reconstruct, pixman_kernel_t sample, +double* size, int* subsample_bits) +{ +return ceil (filters[reconstruct].width + *size * filters[sample].width); +} + /* Create the parameter list for a SEPARABLE_CONVOLUTION filter * with the given kernels and size parameters */ @@ -352,42 +352,35 @@ pixman_filter_create_separable_convolution (int *n_values, { double sx = fabs (pixman_fixed_to_double (size_x)); double sy = fabs (pixman_fixed_to_double (size_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, , _bits_x); 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, , _bits_y); +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 http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 08/15] pixman-filter: Corrections to the integral() function
From: Bill SpitzakThe 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. I fixed the nice filter and the integration to directly produce normalized values. Re-normalization is still needed for impulse.box or impulse.triangle so I did not remove it. Distribute fixed error over all filter samples, to remove a high-frequency bit of noise in the center of some filters (lancoz at large scale value). box.box, which I expect will be very common as it is the proposed "good" filter, was made a lot faster and more accurate. This is easy as the caller already intersected the two boxes, so the width is the integral. v7: This is a merge of 4 patches and lots of new code cleanup and fixes determined by examining the gnuplot output v9: Restored the recursion splitting at zero for linear filter v10: Small change from here moved to previous Simpsons patch so it compiles Merged patch to get correct subsample positions when subsample_bits==0 Signed-off-by: Bill Spitzak --- pixman/pixman-filter.c | 144 + 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 13ee024..bd4e174 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -79,7 +79,7 @@ sinc (double x) } static double -lanczos (double x, int n) +lanczos (double x, double n) { return sinc (x) * sinc (x * (1.0 / n)); } @@ -99,7 +99,7 @@ lanczos3_kernel (double x) static double nice_kernel (double x) { -return lanczos3_kernel (x * 0.75); +return lanczos3_kernel (x * 0.75) * 0.75; } static double @@ -147,45 +147,51 @@ static const filter_info_t filters[] = { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 }, }; -/* This function scales the @sample filter by @size, then - * aligns @x1 in @reconstruct with @x2 in @sample and - * and integrates the product of the kernels across @width. +/* This function scales the @sample filter by @size, 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 reconstruct, double x1, - pixman_kernel_t sample, double size, double x2, - double width) +integral (pixman_kernel_t reconstruct, + pixman_kernel_t sample, double size, double pos, + double low, double high) { +if (high < low) +{ + return 0.0; +} +else if (sample == PIXMAN_KERNEL_IMPULSE) +{ + return filters[reconstruct].func (-pos); +} +else if (reconstruct == PIXMAN_KERNEL_IMPULSE) +{ + return filters[sample].func (-pos / size) / size; +} +else if (reconstruct == PIXMAN_KERNEL_BOX && sample == PIXMAN_KERNEL_BOX) +{ + assert (high <= low + 1.0); + return (high - low) / size; +} /* 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 && low < 0 && high > 0) { return - integral (reconstruct, x1, sample, size, x2, - x1) + - integral (reconstruct, 0, sample, size, x2 - x1, width + x1); + integral (reconstruct, sample, size, pos, low, 0) + + integral (reconstruct, sample, size, pos, 0, high); } -else if (x2 < 0 && x2 + width > 0) +else if (sample == PIXMAN_KERNEL_LINEAR && low < pos && high > pos) { return - integral (reconstruct, x1, sample, size, x2, - x2) + - integral (reconstruct, x1 - x2, sample, size, 0, width + x2); -} -else if (reconstruct == PIXMAN_KERNEL_IMPULSE) -{ - assert (width == 0.0); - return filters[sample].func (x2 / size); -} -else if (sample == PIXMAN_KERNEL_IMPULSE) -{ - assert (width == 0.0); - return filters[reconstruct].func (x1); + integral (reconstruct, sample, size, pos, low, pos) + + integral (reconstruct, sample, size, pos, pos, high); } else { @@ -197,32 +203,30 @@ integral (pixman_kernel_t reconstruct, double x1, * filter is 6 wide. */ #define N_SEGMENTS 12 -#define SAMPLE(a1, a2) \ - (filters[reconstruct].func ((a1)) * filters[sample].func ((a2) / size)) +#define SAMPLE(a) \ +(filters[reconstruct].func
[Pixman] [PATCH v10 04/15] pixman-image: Added enable-gnuplot config to view filters in gnuplot
From: Bill SpitzakIf 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 Signed-off-by: Bill Spitzak --- configure.ac | 13 + pixman/pixman-filter.c | 45 + 2 files changed, 58 insertions(+) diff --git a/configure.ac b/configure.ac index 6b2134e..8066cb2 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..11c8548 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 http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 12/15] pixman-filter: Made reconstruct==impulse and scale < 1 set scale to 1
From: Bill SpitzakThis replaces settings that don't work (because the filter cannot be normalized) with something that produces an image. v7: First version with this. Previously you got lots of strange garbage filters that depended on the implementation. v10: Moved code to filter_width function 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 520ce92..f28cc29 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -341,7 +341,10 @@ static int filter_width(pixman_kernel_t reconstruct, pixman_kernel_t sample, double* size, int* subsample_bits) { -int width = ceil (filters[reconstruct].width + *size * filters[sample].width); +int width; +if (reconstruct == PIXMAN_KERNEL_IMPULSE && *size < 1.0) + *size = 1.0; +width = ceil (filters[reconstruct].width + *size * filters[sample].width); if (width <= 1) { width = 1; -- 1.9.1 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 14/15] pixman-filter: Add description to pixman_filter_create_separable_convolution()
From: Bill Spitzakv9: Described arguments and more filter combinations, fixed some errors. Signed-off-by: Bill Spitzak Reviewed-by: Oded Gabbay --- pixman/pixman-filter.c | 45 + 1 file changed, 45 insertions(+) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 6e8024a..d795573 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -379,6 +379,51 @@ filter_width(pixman_kernel_t reconstruct, pixman_kernel_t sample, /* Create the parameter list for a SEPARABLE_CONVOLUTION filter * with the given kernels and size parameters + * + * Returns pointer to the block of numbers + * + * n_values: pointer to integer to store size of the block + * + * scale_x/y: amount to stretch the sample filter. Note that scale + * is the inverse of how the image is being scaled, if the image is + * being made smaller, the filter gets larger. + * + * reconstruct_x/y: filter that is not scaled. + * + * sample_x/y: filter that is scaled. Resoult is convolved with reconstruct filter. + * + * subsample_bits_x/y: If positive there are 2^n subpixel positions computed for + * the filter. If negative then -n (rounded up to the next power of 2) positions + * are calculated when scale==1, but fewer are computed for larger scales and + * more for smaller scales. + * + * Some interesting reconstruct.sample combinations: + * + * IMPULSE.x - Uses the sample function only. This is what many other pieces of + * software do. Does not work for scale < 1.0. + * + * BOX.x - For scale < 1.0 this produces square pixels. For scale > 1.0 this + * approaches IMPULSE.x as scale gets larger. + * + * x.IMPULSE - Uses the reconstruct function only, scale is ignored. + * + * BOX.BOX, LINEAR.IMPULSE, IMPULSE.LINEAR - at scale==1 these all match and + * also produce same result as bilinear filtering. + * + * BOX.BOX - Produces a trapazoid-shape. Narrowest possible filter with antialiasing. + *Matches a lot of other software, some call it "box", others call it "linear" + * + * BOX.LINEAR - At scale==1 this is what some software calls a Quadratic filter + * + * IMPULSE.LINEAR - Some software calls this "linear" or "triangle". Not a good filter. + * + * LINEAR.LINEAR - non-negative cubic. What some software calls "cubic interpolation". + * + * IMPULSE.LANCZOS2 - Close to what a lot of other software calls "cubic interpolation" + * + * IMPULSE.CUBIC - Called "Mitchell" in other software + * + * IMPULSE.GAUSSIAN - Best removal of aliasing but usually considered too blurry */ PIXMAN_EXPORT pixman_fixed_t * pixman_filter_create_separable_convolution (int *n_values, -- 1.9.1 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 15/15] pixman-image: Implement PIXMAN_FILTER_GOOD/BEST as separable convolutions
From: Bill SpitzakDetects 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. This is compatable at these scales with older versions of pixman where bilinear was always used for GOOD. 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.333 : 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) v8: Cutoff in BEST between IMPULSE.LANCZOS2 and BOX.LANCZOS2 adjusted for a better match between the filters. v9: Use the new negative subsample controls to scale the subsamples. These were chosen by finding the lowest number that did not add visible artifacts to the zone plate image. Scale demo altered to default to GOOD and locked-together x+y scale Fixed divide-by-zero from all-zero matrix found by stress-test Signed-off-by: Bill Spitzak --- demos/scale.c | 10 +- demos/scale.ui| 1 + pixman/pixman-image.c | 289 -- 3 files changed, 216 insertions(+), 84 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index 881004e..3df4442 100644 --- a/demos/scale.c +++ b/demos/scale.c @@ -340,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; @@ -366,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); } @@ -374,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 * @@ -422,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"), diff --git a/demos/scale.ui b/demos/scale.ui index 1e77f56..13e0e0d 100644 --- a/demos/scale.ui +++ b/demos/scale.ui @@ -177,6 +177,7 @@ id="lock_checkbutton"> Lock X and Y Dimensions 0.0 + True False diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c index 1ff1a49..c381260 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,242 @@ 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 nearest_ok, bilinear_ok; + flags |= FAST_PATH_HAS_TRANSFORM; - if (image->common.transform->matrix[2][0] == 0 && - image->common.transform->matrix[2][1]
[Pixman] [PATCH v10 13/15] pixman-filter: Negative subsample values produces scaled result
From: Bill SpitzakIf a negative value is used for the subsampling, then -n subsamples are used at scale==1, and fewer are used at larger scale, more are used at smaller scale, so that the total number of samples is approximately the same. The computed value is rounded up to the next power of 2. The scale demo is modified to allow these negative numbers, and initially uses -12. Signed-off-by: Bill Spitzak --- demos/scale.ui | 5 +++-- pixman/pixman-filter.c | 24 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/demos/scale.ui b/demos/scale.ui index b62cbfb..1e77f56 100644 --- a/demos/scale.ui +++ b/demos/scale.ui @@ -24,12 +24,12 @@ 10 -0 +-256 12 1 1 0 -4 +-12 @@ -321,6 +321,7 @@ True subsample_adjustment + -12 1 diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index f28cc29..6e8024a 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -342,14 +342,38 @@ filter_width(pixman_kernel_t reconstruct, pixman_kernel_t sample, double* size, int* subsample_bits) { int width; +/* IMPULSE.x does not work for size < 1.0 */ if (reconstruct == PIXMAN_KERNEL_IMPULSE && *size < 1.0) *size = 1.0; +/* Convolution adds the widths of the filters together */ width = ceil (filters[reconstruct].width + *size * filters[sample].width); +/* If there will only be one sample, it must be 1.0 due to normalization, + and subsampling is useless. */ if (width <= 1) { width = 1; *subsample_bits = 0; } +else if (*subsample_bits < 0) +{ + /* The intention was to do -n / size rounded up to the next power of 2, + but this non-linear function seems to work better. For large size + it is the width of the BOX.BOX filter. For small size it reduces + samples by 2 at maximum. */ + double desired_samples = -*subsample_bits; + if (sample == PIXMAN_KERNEL_IMPULSE) + ; /* For x.IMPULSE no scaling is done */ + else if (*size >= 1.0) + desired_samples *= 2.0 / (*size + 1.0); + else + desired_samples *= 2.0 / ((*size + 1.0) * *size); + *subsample_bits = (int) ceil (log2(desired_samples) - .01); + if (*subsample_bits < 0) + *subsample_bits = 0; + else if (*subsample_bits > 8) + /* Assume we cannot see more than 256 different shades and limit subsampling */ + *subsample_bits = 8; +} return width; } -- 1.9.1 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 11/15] pixman-filter: Turn off subsampling for width=1 filters
From: Bill SpitzakDue to normalization these filters must all be identical (a single 1.0). Also make IMPULSE.IMPULSE produce a width=1 filter, rather than zero (which did not work). v7: Replaced earlier tests for BOX.IMPULSE v10: Moved code to filter_width function Signed-off-by: Bill Spitzak --- pixman/pixman-filter.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 10fa398..520ce92 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -341,7 +341,13 @@ static int filter_width(pixman_kernel_t reconstruct, pixman_kernel_t sample, double* size, int* subsample_bits) { -return ceil (filters[reconstruct].width + *size * filters[sample].width); +int width = ceil (filters[reconstruct].width + *size * filters[sample].width); +if (width <= 1) +{ + width = 1; + *subsample_bits = 0; +} +return width; } /* Create the parameter list for a SEPARABLE_CONVOLUTION filter -- 1.9.1 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 01/15] demos/scale: Compute filter size using boundary of xformed ellipse, not rectangle
From: Bill SpitzakThis is much more accurate and less blurry. In particular the filtering does not change as the image is rotated. Signed-off-by: Bill Spitzak Reviewed-by: Oded Gabbay --- demos/scale.c | 102 +++--- 1 file changed, 61 insertions(+), 41 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index d00307e..0995ad0 100644 --- a/demos/scale.c +++ b/demos/scale.c @@ -55,50 +55,70 @@ 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); -} - +/* Figure out the boundary of a diameter=1 circle transformed into an ellipse + * by trans. Proof that this is the correct calculation: + * + * Transform x,y to u,v by this matrix calculation: + * + * |u| |a c| |x| + * |v| = |b d|*|y| + * + * Horizontal component: + * + * u = ax+cy (1) + * + * For each x,y on a radius-1 circle (p is angle to the point): + * + * x^2+y^2 = 1 + * x = cos(p) + * y = sin(p) + * dx/dp = -sin(p) = -y + * dy/dp = cos(p) = x + * + * Figure out derivative of (1) relative to p: + * + * du/dp = a(dx/dp) + c(dy/dp) + *= -ay + cx + * + * The min and max u are when du/dp is zero: + * + * -ay + cx = 0 + * cx = ay + * c = ay/x (2) + * y = cx/a (3) + * + * Substitute (2) into (1) and simplify: + * + * u = ax + ay^2/x + *= a(x^2+y^2)/x + *= a/x (because x^2+y^2 = 1) + * x = a/u (4) + * + * Substitute (4) into (3) and simplify: + * + * y = c(a/u)/a + * y = c/u (5) + * + * Square (4) and (5) and add: + * + * x^2+y^2 = (a^2+c^2)/u^2 + * + * But x^2+y^2 is 1: + * + * 1 = (a^2+c^2)/u^2 + * u^2 = a^2+c^2 + * u = hypot(a,c) + * + * Similarily the max/min of v is at: + * + * v = hypot(b,d) + * + */ 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 v10 03/15] demos/scale: Only generate filters when used for separable
From: Bill SpitzakThis makes the speed of the demo more accurate, as the filter generation is a visible fraction of the time it takes to do a transform. This also prevents the output of unused filters in the gnuplot option in the next patch. Signed-off-by: Bill Spitzak --- demos/scale.c | 29 +++-- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index 06821e3..881004e 100644 --- a/demos/scale.c +++ b/demos/scale.c @@ -258,16 +258,25 @@ rescale (GtkWidget *may_be_null, app_t *app) pixman_transform_from_pixman_f_transform (, ); pixman_image_set_transform (app->original, ); -params = pixman_filter_create_separable_convolution ( -_params, -sx * 65536.0 + 0.5, - sy * 65536.0 + 0.5, - get_value (app, filters, "reconstruct_x_combo_box"), - get_value (app, filters, "reconstruct_y_combo_box"), - get_value (app, filters, "sample_x_combo_box"), - get_value (app, filters, "sample_y_combo_box"), - gtk_adjustment_get_value (app->subsample_adjustment), - gtk_adjustment_get_value (app->subsample_adjustment)); +if (get_value (app, filter_types, "filter_combo_box") == + PIXMAN_FILTER_SEPARABLE_CONVOLUTION) +{ + params = pixman_filter_create_separable_convolution ( +_params, + sx * 65536.0 + 0.5, + sy * 65536.0 + 0.5, + get_value (app, filters, "reconstruct_x_combo_box"), + get_value (app, filters, "reconstruct_y_combo_box"), + get_value (app, filters, "sample_x_combo_box"), + get_value (app, filters, "sample_y_combo_box"), + gtk_adjustment_get_value (app->subsample_adjustment), + gtk_adjustment_get_value (app->subsample_adjustment)); +} +else +{ + params = 0; + n_params = 0; +} pixman_image_set_filter (app->original, get_value (app, filter_types, "filter_combo_box"), -- 1.9.1 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 05/15] pixman-filter: Consistency in arg names to integral ()
From: Bill SpitzakRename kernel1/2 to reconstruct/sample to match the other functions. Rename "scale" to "size" to avoid confusion with the scale being applied to the image, which is the reciprocol of this value. v10: Renamed "scale" to "size" Signed-off-by: Bill Spitzak Reviewed-by: Oded Gabbay --- pixman/pixman-filter.c | 48 +++- pixman/pixman.h| 6 +++--- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 11c8548..acfb110 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 the @sample filter by @size, 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 size, 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, size, x2, - x1) + + integral (reconstruct, 0, sample, size, 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, size, x2, - x2) + + integral (reconstruct, x1 - x2, sample, size, 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 / size); } -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) / size)) double s = 0.0; double h = width / (double)N_SEGMENTS; @@ -221,16 +221,14 @@ static pixman_fixed_t * create_1d_filter (int *width, pixman_kernel_t reconstruct, pixman_kernel_t sample, - double scale, + double size, int n_phases) { pixman_fixed_t *params, *p; double step; -double size; int i; -size = scale * filters[sample].width + filters[reconstruct].width; -*width = ceil (size); +*width = ceil (size * filters[sample].width + filters[reconstruct].width); p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t)); if (!params) @@ -259,8 +257,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; @@ -270,7 +268,7 @@ create_1d_filter (int *width, ihigh = MIN (shigh, rhigh); c = integral (reconstruct, ilow, - sample, 1.0 / scale, ilow - pos, + sample, size, ilow - pos, ihigh - ilow); } @@ -339,12 +337,12 @@ gnuplot_filter(int width, int samples, const pixman_fixed_t* p) #endif /* Create the parameter list for a SEPARABLE_CONVOLUTION filter - * with the given kernels and scale parameters + * with the
[Pixman] [PATCH v10 10/15] pixman-filter: Gaussian fixes
From: Bill SpitzakThe SIGMA term drops out on simplification. Expanded the size slightly (from ~4.25 to 5) to make the cutoff less noticable. The filter is truncated at a value of .001 instead of .006, this new value is less than 1/2 of 1/255, rather than greater than it. Signed-off-by: Bill Spitzak Acked-by: Oded Gabbay --- pixman/pixman-filter.c | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index b6f8eb4..10fa398 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -63,10 +63,7 @@ linear_kernel (double x) static double gaussian_kernel (double x) { -#define SQRT2 (1.4142135623730950488016887242096980785696718753769480) -#define SIGMA (SQRT2 / 2.0) - -return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI)); +return exp (- x * x) / sqrt (M_PI); } static double @@ -139,7 +136,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 http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 02/15] demos/scale: Added pulldown to choose PIXMAN_FILTER_* value
From: Bill SpitzakThis allows testing of GOOD/BEST and to do comparisons between the basic filters and PIXMAN_FILTER_SEPARABLE_CONVOLUTION settings. Signed-off-by: Bill Spitzak Reviewed-by: Oded Gabbay --- 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 0995ad0..06821e3 100644 --- a/demos/scale.c +++ b/demos/scale.c @@ -127,6 +127,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 }, @@ -260,7 +269,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 +413,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 @@
[Pixman] [PATCH v10] Implement PIXMAN_FILTER_GOOD/BEST
Changes from previous version: - Some refactor to reduce size of each patch - Fixed rebase error that made some patches not compile - Renamed "scale" to "size" to avoid confusion with the transform scale Compatibiliy notes: For the default filter of GOOD this produces the same BILINEAR result for any scale greater than 3/4, and also for a scale of 1/2 if there is no rotation or translation. For BEST the output is changed for all transforms other than the identity. For other filter settings the result is unchanged. These changes match those done to Cairo about 1.5 years ago, with the same amount of incompatability. Making these changes will allow Cairo to use pixman directly rather than generate it's own filters. ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v10 09/15] pixman-filter: don't range-check in filter functions
From: Bill SpitzakThe integral will not be called outside the width so there is no need to check against these. v9: merged commits for cubic and impulse into same one Signed-off-by: Bill Spitzak --- pixman/pixman-filter.c | 18 -- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index bd4e174..b6f8eb4 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 @@ -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 v10 07/15] pixman-filter: Correct Simpsons integration
From: Bill SpitzakSimpsons 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. Since it divided by 3 this produced about 2x the desired value (the normalization fixed this). Also this is effectively a linear interpolation, not Simpsons integration. 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 Signed-off-by: Bill Spitzak --- pixman/pixman-filter.c | 25 + 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 6c077b6..13ee024 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -189,13 +189,19 @@ integral (pixman_kernel_t reconstruct, 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[reconstruct].func ((a1)) * filters[sample].func ((a2) / size)) - + 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 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
Re: [Pixman] [PATCH v9 05/15] pixman-filter: reduce amount of malloc/free/memcpy to generate filter
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > 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 > > v1: first version No need for as the commit message represents that. > > Signed-off-by: Bill Spitzak > --- > pixman/pixman-filter.c | 51 > +- > 1 file changed, 17 insertions(+), 34 deletions(-) > > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > index aaa7de9..55073c4 100644 > --- a/pixman/pixman-filter.c > +++ b/pixman/pixman-filter.c > @@ -217,25 +217,17 @@ integral (pixman_kernel_t reconstruct, 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; > } > > #if PIXMAN_GNUPLOT > @@ -354,38 +344,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 = ceil (filters[reconstruct_x].width + sx * > filters[sample_x].width); > +height = ceil (filters[reconstruct_y].width + sy * > filters[sample_y].width); > > -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); > > #if PIXMAN_GNUPLOT > gnuplot_filter(width, subsample_x, params+4); > -- > 1.9.1 > > ___ > Pixman mailing list > Pixman@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/pixman With the v1: removed, consider this patch: Reviewed-by: Oded Gabbay ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 06/15] pixman-filter: Correct Simpsons integration
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > 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. Since it divided by > 3 this produced about 2x the desired value (the normalization fixed this). > Also this is effectively a linear interpolation, not Simpsons integration. > > 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. > > v9: Changed samples from 16 to 12 > v7: Merged with patch to reduce from 128 samples to 16 > > Signed-off-by: Bill Spitzak > --- > pixman/pixman-filter.c | 29 +++-- > 1 file changed, 19 insertions(+), 10 deletions(-) > > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > index 55073c4..718649a 100644 > --- a/pixman/pixman-filter.c > +++ b/pixman/pixman-filter.c > @@ -189,13 +189,19 @@ integral (pixman_kernel_t reconstruct, double x1, > } > else > { > - /* Integration via Simpson's rule */ > -#define N_SEGMENTS 128 > -#define SAMPLE(a1, a2) \ > - (filters[reconstruct].func ((a1)) * filters[sample].func ((a2) / > scale)) > - > + /* 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(a) \ > + (filters[reconstruct].func ((a)) * filters[sample].func (((a) - pos) > / scale)) > + You changed the SAMPLE macro to get 1 parameter, but in all the calls you send 2 parameters, which make the compilation fail. Please fix this and resend the patch. Oded > 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 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 mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 04/15] pixman-filter: Consistency in arg names to integral ()
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > From: Bill Spitzak > > Rename kernel1/2 to reconstruct/sample and use 1/scale as the > scale argument, thus matching the names in other functions. > > Signed-off-by: Bill Spitzak > --- > 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 fe0d261..aaa7de9 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 Reviewed-by: Oded Gabbay ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 14/15] pixman-filter: Added big comment to filter
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > From: Bill Spitzak > The title of the patch confused me a bit. Maybe rewrite it as: pixman-filter: Add description to pixman_filter_create_separable_convolution() > v9: Described arguments and more filter combinations, fixed some errors. > v8: first version No need of v8:first version > > Signed-off-by: Bill Spitzak > --- > pixman/pixman-filter.c | 46 +- > 1 file changed, 45 insertions(+), 1 deletion(-) > > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > index 639d5e6..74819fe 100644 > --- a/pixman/pixman-filter.c > +++ b/pixman/pixman-filter.c > @@ -378,7 +378,51 @@ filter_width(pixman_kernel_t reconstruct, > pixman_kernel_t sample, > } > > /* Create the parameter list for a SEPARABLE_CONVOLUTION filter > - * with the given kernels and scale parameters > + * > + * Returns pointer to the block of numbers > + * > + * n_values: pointer to integer to store size of the block > + * > + * scale_x/y: amount to stretch the sample filter. Note that scale > + * is the inverse of how the image is being scaled, if the image is > + * being made smaller, the filter gets larger. > + * > + * reconstruct_x/y: filter that is not scaled. > + * > + * sample_x/y: filter that is scaled. Resoult is convolved with reconstruct > filter. > + * > + * subsample_bits_x/y: If positive there are 2^n subpixel positions computed > for > + * the filter. If negative then -n (rounded up to the next power of 2) > positions > + * are calculated when scale==1, but fewer are computed for larger scales and > + * more for smaller scales. > + * > + * Some interesting reconstruct.sample combinations: > + * > + * IMPULSE.x - Uses the sample function only. This is what many other > pieces of > + * software do. Does not work for scale < 1.0. > + * > + * BOX.x - For scale < 1.0 this produces square pixels. For scale > 1.0 this > + * approaches IMPULSE.x as scale gets larger. > + * > + * x.IMPULSE - Uses the reconstruct function only, scale is ignored. > + * > + * BOX.BOX, LINEAR.IMPULSE, IMPULSE.LINEAR - at scale==1 these all match and > + * also produce same result as bilinear filtering. > + * > + * BOX.BOX - Produces a trapazoid-shape. Narrowest possible filter with > antialiasing. > + *Matches a lot of other software, some call it "box", others > call it "linear" > + * > + * BOX.LINEAR - At scale==1 this is what some software calls a Quadratic > filter > + * > + * IMPULSE.LINEAR - Some software calls this "linear" or "triangle". Not a > good filter. > + * > + * LINEAR.LINEAR - non-negative cubic. What some software calls "cubic > interpolation". > + * > + * IMPULSE.LANCZOS2 - Close to what a lot of other software calls "cubic > interpolation" > + * > + * IMPULSE.CUBIC - Called "Mitchell" in other software > + * > + * IMPULSE.GAUSSIAN - Best removal of aliasing but usually considered too > blurry > */ > PIXMAN_EXPORT pixman_fixed_t * > pixman_filter_create_separable_convolution (int *n_values, > -- > 1.9.1 > > ___ > Pixman mailing list > Pixman@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/pixman With those changes, this patch is: Reviewed-by: Oded Gabbay ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 07/15] pixman-filter: Corrections to the integral() function
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > 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. > > I fixed the nice filter and the integration to directly produce normalized > values. Re-normalization is still needed for impulse.box or impulse.triangle > so I did not remove it. > > Distribute fixed error over all filter samples, to remove a high-frequency > bit of noise in the center of some filters (lancoz at large scale value). > > box.box, which I expect will be very common as it is the proposed "good" > filter, > was made a lot faster and more accurate. This is easy as the caller already > intersected the two boxes, so the width is the integral. > > v9: Restored the recursion splitting at zero for linear filter > v7: This is a merge of 4 patches and lots of new code cleanup and fixes > determined by examining the gnuplot output > > Signed-off-by: Bill Spitzak > --- > pixman/pixman-filter.c | 135 > + > 1 file changed, 68 insertions(+), 67 deletions(-) > > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > index 718649a..768e1f6 100644 > --- a/pixman/pixman-filter.c > +++ b/pixman/pixman-filter.c > @@ -79,7 +79,7 @@ sinc (double x) > } > > static double > -lanczos (double x, int n) > +lanczos (double x, double n) > { > return sinc (x) * sinc (x * (1.0 / n)); > } > @@ -99,7 +99,7 @@ lanczos3_kernel (double x) > static double > nice_kernel (double x) > { > -return lanczos3_kernel (x * 0.75); > +return lanczos3_kernel (x * 0.75) * 0.75; > } > > static double > @@ -147,45 +147,51 @@ static const filter_info_t filters[] = > { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 }, > }; > > -/* 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 scales @sample 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 reconstruct, double x1, > - pixman_kernel_t sample, double scale, double x2, > - double width) > +integral (pixman_kernel_t reconstruct, > + pixman_kernel_t sample, double scale, double pos, > + double low, double high) > { > +if (high < low) > +{ > + return 0.0; > +} > +else if (sample == PIXMAN_KERNEL_IMPULSE) > +{ > + return filters[reconstruct].func (-pos); > +} > +else if (reconstruct == PIXMAN_KERNEL_IMPULSE) > +{ > + return filters[sample].func (-pos / scale) / scale; > +} > +else if (reconstruct == PIXMAN_KERNEL_BOX && sample == 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 > * integrate properly. > */ > -if (x1 < 0 && x1 + width > 0) > +else if (reconstruct == PIXMAN_KERNEL_LINEAR && low < 0 && high > 0) > { > return > - integral (reconstruct, x1, sample, scale, x2, - x1) + > - integral (reconstruct, 0, sample, scale, x2 - x1, width + x1); > + integral (reconstruct, sample, scale, pos, low, 0) + > + integral (reconstruct, sample, scale, pos, 0, high); > } > -else if (x2 < 0 && x2 + width > 0) > +else if (sample == PIXMAN_KERNEL_LINEAR && low < pos && high > pos) > { > 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 (sample == PIXMAN_KERNEL_IMPULSE) > -{ > - assert (width == 0.0); > - return filters[reconstruct].func (x1); > + integral (reconstruct, sample, scale, pos, low, pos) + > + integral (reconstruct, sample, scale, pos, pos, high); > } > else > { > @@ -201,28 +207,26 @@ integral (pixman_kernel_t reconstruct, double x1, > (filters[reconstruct].func ((a)) * filters[sample].func (((a) - pos) > / scale)) > > double s = 0.0; > - double h = width / N_SEGMENTS; > + double h = (high
Re: [Pixman] [PATCH v9 10/15] pixman-filter: Gaussian fixes
On Fri, Jan 22, 2016 at 11:42 AM,wrote: > From: Bill Spitzak > > The SIGMA term drops out on simplification. > > Expanded the size slightly (from ~4.25 to 5) to make the cutoff less > noticable. > The filter is truncated at a value of .001 instead of .006, this new > value is less than 1/2 of 1/255, rather than greater than it. > > v1: initial version No need for v1: > > Signed-off-by: Bill Spitzak > --- > pixman/pixman-filter.c | 7 ++- > 1 file changed, 2 insertions(+), 5 deletions(-) > > diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c > index 3062448..20d0fcb 100644 > --- a/pixman/pixman-filter.c > +++ b/pixman/pixman-filter.c > @@ -63,10 +63,7 @@ linear_kernel (double x) > static double > gaussian_kernel (double x) > { > -#define SQRT2 (1.4142135623730950488016887242096980785696718753769480) > -#define SIGMA (SQRT2 / 2.0) > - > -return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI)); > +return exp (- x * x) / sqrt (M_PI); > } > > static double > @@ -139,7 +136,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 > http://lists.freedesktop.org/mailman/listinfo/pixman With v1: removed, this patch is Acked-by: Oded Gabbay ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 03/15] pixman-image: Added enable-gnuplot config to view filters in gnuplot
On Mon, Feb 1, 2016 at 6:11 AM, Oded Gabbaywrote: > On Mon, Feb 1, 2016 at 4:10 PM, Oded Gabbay wrote: > > On Fri, Jan 22, 2016 at 11:42 AM, wrote: > >> 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 > >> > >> v8: Use config option > >> Moved code to the filter generator > >> Modified scale demo to not call filter generator a second time. > >> > >> v7: First time this ability was included > > One more thing. The vX comments should be ordered from first to last > (old to new), so: > v7: ... > v8: ... > Okay thank you, I will fix all of them. ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 03/15] pixman-image: Added enable-gnuplot config to view filters in gnuplot
On Mon, Feb 1, 2016 at 6:10 AM, Oded Gabbaywrote: > > > -params = pixman_filter_create_separable_convolution ( > > -_params, > > -sx * 65536.0 + 0.5, > > - sy * 65536.0 + 0.5, > > - get_value (app, filters, "reconstruct_x_combo_box"), > > - get_value (app, filters, "reconstruct_y_combo_box"), > > - get_value (app, filters, "sample_x_combo_box"), > > - get_value (app, filters, "sample_y_combo_box"), > > - gtk_adjustment_get_value (app->subsample_adjustment), > > - gtk_adjustment_get_value (app->subsample_adjustment)); > > +if (get_value (app, filter_types, "filter_combo_box") == > > + PIXMAN_FILTER_SEPARABLE_CONVOLUTION) > > +{ > > + params = pixman_filter_create_separable_convolution ( > > +_params, > > + sx * 65536.0 + 0.5, > > + sy * 65536.0 + 0.5, > > + get_value (app, filters, "reconstruct_x_combo_box"), > > + get_value (app, filters, "reconstruct_y_combo_box"), > > + get_value (app, filters, "sample_x_combo_box"), > > + get_value (app, filters, "sample_y_combo_box"), > > + gtk_adjustment_get_value (app->subsample_adjustment), > > + gtk_adjustment_get_value (app->subsample_adjustment)); > > +} > > +else > > +{ > > + params = 0; > > + n_params = 0; > > +} > > Wait, what the above code has to do with this patch ? > It wasn't in the previous version (v7) and I don't see how it is > related to the gnuplot. > This seems like a fix to the demo code. > If what I said is correct, please split it into a different patch. > I had to patch it so it did not run the filter generator twice when set to good/best, otherwise the plot flashed back and forth annoyingly. But this also makes the demo a bit faster showing accurately the speed at which transforms are done, so I think putting this in an earlier patch is a good idea. > +#if PIXMAN_GNUPLOT > > To keep consistency with other defines checks, please use #ifdef when > checking just one define > OK > > @@ -346,5 +387,9 @@ out: > > free (horz); > > free (vert); > > > > +#if PIXMAN_GNUPLOT > > To keep consistency with other defines checks, please use #ifdef when > checking just one define > > > +gnuplot_filter(width, subsample_x, params+4); > > +#endif > > + > > What's the point in printing the filter after the out: label ? > You can get here in cases where there were errors in the function. > Why not put the call to gnuplot_filter() just before the out: label ? > You are correct it should only do this on success. My mistake. ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v9 01/15] demos/scale: Compute filter size using boundary of xformed ellipse, not rectangle
Okay, thanks for the info. Will try to fix them all. On Mon, Feb 1, 2016 at 5:51 AM, Oded Gabbaywrote: > On Fri, Jan 22, 2016 at 11:41 AM, wrote: > > > > From: Bill Spitzak > > > > This is much more accurate and less blurry. In particular the filtering > does > > not change as the image is rotated. > > > > Signed-off-by: Bill Spitzak > > --- > > demos/scale.c | 102 > +++--- > > 1 file changed, 61 insertions(+), 41 deletions(-) > > > > diff --git a/demos/scale.c b/demos/scale.c > > index d00307e..0995ad0 100644 > > --- a/demos/scale.c > > +++ b/demos/scale.c > > @@ -55,50 +55,70 @@ 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); > > -} > > - > > +/* Figure out the boundary of a diameter=1 circle transformed into an > ellipse > > + * by trans. Proof that this is the correct calculation: > > + * > > + * Transform x,y to u,v by this matrix calculation: > > + * > > + * |u| |a c| |x| > > + * |v| = |b d|*|y| > > + * > > + * Horizontal component: > > + * > > + * u = ax+cy (1) > > + * > > + * For each x,y on a radius-1 circle (p is angle to the point): > > + * > > + * x^2+y^2 = 1 > > + * x = cos(p) > > + * y = sin(p) > > + * dx/dp = -sin(p) = -y > > + * dy/dp = cos(p) = x > > + * > > + * Figure out derivative of (1) relative to p: > > + * > > + * du/dp = a(dx/dp) + c(dy/dp) > > + *= -ay + cx > > + * > > + * The min and max u are when du/dp is zero: > > + * > > + * -ay + cx = 0 > > + * cx = ay > > + * c = ay/x (2) > > + * y = cx/a (3) > > + * > > + * Substitute (2) into (1) and simplify: > > + * > > + * u = ax + ay^2/x > > + *= a(x^2+y^2)/x > > + *= a/x (because x^2+y^2 = 1) > > + * x = a/u (4) > > + * > > + * Substitute (4) into (3) and simplify: > > + * > > + * y = c(a/u)/a > > + * y = c/u (5) > > + * > > + * Square (4) and (5) and add: > > + * > > + * x^2+y^2 = (a^2+c^2)/u^2 > > + * > > + * But x^2+y^2 is 1: > > + * > > + * 1 = (a^2+c^2)/u^2 > > + * u^2 = a^2+c^2 > > + * u = hypot(a,c) > > + * > > + * Similarily the max/min of v is at: > > + * > > + * v = hypot(b,d) > > + * > > + */ > > 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 > > Reviewed-by: Oded Gabbay > > p.s. if we have additional versions of this patch series, and patches > that got r-b are not modified, then please add my r-b to the patch so > I would know I don't need to spend even a second over that patch. > > Thanks > ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman