[Pixman] [PATCH v14 18/22] pixman-filter: Made Gaussian a bit wider
From: Bill SpitzakExpanded 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
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 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
From: Bill SpitzakIt 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
From: Bill SpitzakThis 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
From: Bill SpitzakThe 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
From: Bill SpitzakAllows 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
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 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
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,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
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. 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
From: Bill Spitzakv11: 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
From: Bill SpitzakThis 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
From: Bill SpitzakOnly 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
From: Bill SpitzakThis 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
From: Bill SpitzakThis 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
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
From: Bill SpitzakThe 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