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; > +
[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]