Re: [Pixman] [PATCH v10 10/15] pixman-filter: Gaussian fixes
On Tue, Feb 2, 2016 at 8:28 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. I'm just wondering how did you get to this result ? Oded > > 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 mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v10 06/15] pixman-filter: reduce amount of malloc/free/memcpy to generate filter
On Tue, Feb 2, 2016 at 8:28 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 > > v10: Restored filter_width function but with arguments changed to > match later patches > > Signed-off-by: Bill Spitzak > > Reviewed-by: Oded Gabbay When you change and then re-change the patch, you definitely can't keep this tag :) Only when you resend it without *any* changes or when you fix according to a specific comment you can keep it. > --- > 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 */ Well, it doesn't modify them, so I think we should match the comment to the function, no ? And if you intend to change it in the future, then specifically write it like that, i.e. "in the future, this function can be re-written to also modify the size & subsample bits" > +static int > +filter_width(pixman_kernel_t reconstruct, pixman_kernel_t sample, > +double* size, int* subsample_bits) 1. Why do we need *subsample_bits if we don't use it in the function ? Please remove it. 2. Why pass size as pointer ? We don't change it, so why not by value ? And if in the future you do want to change them, then do it in the future patches, not here. It is very confusing. > +{ > +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; > >
Re: [Pixman] [PATCH v10 08/15] pixman-filter: Corrections to the integral() function
On Tue, Feb 2, 2016 at 8:28 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. > > 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
Re: [Pixman] [PATCH v10 12/15] pixman-filter: Made reconstruct==impulse and scale < 1 set scale to 1
On Tue, Feb 2, 2016 at 8:28 AM,wrote: > From: Bill Spitzak > > This 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 I would need to see some form of test/example that is affected by this patch, as I don't have the knowledge to even ACK it. Otherwise, you will need to get someone else to review this (Soren ?). Oded ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v10 11/15] pixman-filter: Turn off subsampling for width=1 filters
On Tue, Feb 2, 2016 at 8:28 AM,wrote: > From: Bill Spitzak > > Due 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 I would need to see some form of test/example that is affected by this patch, as I don't have the knowledge to even ACK it. Otherwise, you will need to get someone else to review this (Soren ?). Oded ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v11 08/14] 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 v11: Whitespace fixes Signed-off-by: Bill Spitzak Acked-by: Oded Gabbay --- pixman/pixman-filter.c | 154 + 1 file changed, 79 insertions(+), 75 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 8b8fb82..e82871f 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)
[Pixman] [PATCH v11 12/14] pixman-filter: Add description to pixman_filter_create_separable_convolution()
From: Bill Spitzakv9: Described arguments and more filter combinations, fixed some errors. v11: Further correction, in particular replaced "scale" with "size" Signed-off-by: Bill Spitzak --- pixman/pixman-filter.c | 50 ++ 1 file changed, 50 insertions(+) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index e57b154..b23d348 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -379,6 +379,56 @@ subsample_bits (int subsample_bits, pixman_kernel_t sample, double size) /* 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 + * + * size_x/y: amount to stretch the sample filter. The best value to + * use is the derivative of the sample location. This value is + * approximately 1/scale when scaling an image. If size < 1.0 then you + * will get square pixels as an image is enlarged, using 1.0 instead + * will get the more customary "blurry" enlargement. + * + * reconstruct_x/y: filter that is not resized. + * + * sample_x/y: filter that is resized. Result 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 size==1, but fewer are computed for larger sizes and + * more for smaller sizes. + * + * 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 size < 1.0. + * + * x.IMPULSE - Uses the reconstruct function only, size is ignored. This is + * what many pieces of software do for size < 1.0. + * + * LINEAR.IMPULSE - Same as the bilinear filter + * + * 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". At size==1 this matches LINEAR.IMPULSE, IMPULSE.LINEAR, and + *the bilinear filter, allowing transitions at those points. + * + * BOX.x - For size < 1.0 this produces square pixels. For size > 1.0 this + * approaches IMPULSE.x as size gets larger. + * + * BOX.LINEAR - At size==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 - At size==1 this is what some software calls "cubic interpolation". + * + * IMPULSE.LANCZOS2 - Close to what a lot of other software calls "cubic interpolation" + * + * IMPULSE.CUBIC - A third thing often called "cubic interpolation", sometimes 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 v11 05/14] 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 3981c8b..b70da1f 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 v11 14/14] demos/scale: default to GOOD and locked-together axis
From: Bill SpitzakThis makes the demo match normal behavior of pixman/cairo at startup. Signed-off-by: Bill Spitzak --- demos/scale.c | 10 +- demos/scale.ui | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index 6d7ad2a..d1fce5d 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 -- 1.9.1 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v11 02/14] 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 v11] Implement PIXMAN_FILTER_GOOD/BEST
Changes form previous version: - whitespace and formatting fixes - removed "fixes" for IMPULSE.x at size < 1 or IMPULSE.IMPULSE, just let them produce unusable filters, since caller can avoid doing this. - removed patch that deleted range checks - simplification of the filter_width function - fixed the comment to use "size" instead of "scale" ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v11 04/14] 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..3981c8b 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 v11 03/14] 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 Reviewed-by: Oded Gabbay --- demos/scale.c | 29 +++-- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index 06821e3..6d7ad2a 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 v11 06/14] 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 --- pixman/pixman-filter.c | 55 +- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index b70da1f..69ac3ab 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,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 size parameters */ @@ -352,42 +350,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, 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 http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH v11 09/14] pixman-filter: Nested polynomial for cubic
From: Bill Spitzakv11: Restored range checks Signed-off-by: Bill Spitzak --- 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 e82871f..e5ef8e6 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 http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH 1/2] Add test for _intersect_rect(, )
Hello Bill, Thanks for the patches. By the way, they are a little bit mangled, maybe because you did not use "git send-email" to send them? This is easily fixable for small patches like this, but may become a problem for larger patch sets. On Tue, 2 Feb 2016 17:35:28 -0800 Bill McCloskeywrote: > This test ensures that calling _intersect_rect on an empty > rectangle produces an empty region. > > Reviewed-by: Siarhei Siamashka Your "Signed-off-by: Bill McCloskey " should be also here. Also adding my "Reviewed-by" was a little bit premature because I had no idea how this patch would look in the end. I only promised that getting my "Reviewed-by" would be easy. > --- > test/region-test.c | 9 + > 1 file changed, 9 insertions(+) > > diff --git a/test/region-test.c b/test/region-test.c > index bfc219b..e5743e8 100644 > --- a/test/region-test.c > +++ b/test/region-test.c > @@ -116,10 +116,19 @@ main () > > assert (pixman_region32_equal (, )); > pixman_region32_fini (); > pixman_region32_fini (); > > } > pixman_image_unref (fill); > > +/* This would produce a region containing an empty > + * rectangle in it. Such regions are considered malformed, > + * but using an empty rectangle for initialization should > + * work. > + */ Do I understand it right that you are trying to describe the implementation details of the current bug in this comment? But after we fix the bug, this description would instantly become obsolete and will just confuse the people reading the code. I think that just using the commit message here would make a perfect comment: "This test ensures that calling _intersect_rect on an empty rectangle produces an empty region." > +pixman_region32_init_rects (, boxes, 3); > +pixman_region32_intersect_rect (, , 11, 11, 0, 0); > +assert (!pixman_region32_not_empty()); This is not too critical, but having "pixman_region32_fini ();" here would be nice. > + > return 0; > } You can send a v2 patch (trying to use "git send-email" this time). Or if you prefer, I can push this patch with the above mentioned adjustments. -- Best regards, Siarhei Siamashka ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
Re: [Pixman] [PATCH v10 15/15] pixman-image: Implement PIXMAN_FILTER_GOOD/BEST as separable convolutions
On 02/04/2016 05:42 AM, Oded Gabbay wrote: On Tue, Feb 2, 2016 at 8:28 AM,wrote: From: Bill Spitzak Detects and uses PIXMAN_FILTER_NEAREST for all 8 90-degree rotations and reflections when the scale is 1.0 and integer translation. GOOD uses: scale < 1/16 : BOX.BOX at size 16 scale < 3/4 : BOX.BOX at size 1/scale larger : BOX.BOX at size 1 If both directions have a scale >= 3/4 or a scale of 1/2 and an integer translation, the faster PIXMAN_FILTER_BILINEAR code is used. 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 Let's separate pixman core changes and demo changes. It's bad for bisectability and maintainability. Do the core changes first, then another patch for the scale demo. 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; +
Re: [Pixman] [PATCH v10 15/15] pixman-image: Implement PIXMAN_FILTER_GOOD/BEST as separable convolutions
On Tue, Feb 2, 2016 at 8:28 AM,wrote: > From: Bill Spitzak > > Detects and uses PIXMAN_FILTER_NEAREST for all 8 90-degree rotations and > reflections when the scale is 1.0 and integer translation. > > GOOD uses: > > scale < 1/16 : BOX.BOX at size 16 > scale < 3/4 : BOX.BOX at size 1/scale > larger : BOX.BOX at size 1 > > If both directions have a scale >= 3/4 or a scale of 1/2 and an integer > translation, the faster PIXMAN_FILTER_BILINEAR code is used. 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 Let's separate pixman core changes and demo changes. It's bad for bisectability and maintainability. Do the core changes first, then another patch for the scale demo. > > 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; > +