[Pixman] [PATCH v13 11/14] pixman-filter: Negative subsample values produces scaled result

spitzak at gmail.com spitzak at gmail.com
Wed Feb 10 06:25:29 UTC 2016


From: Bill Spitzak <spitzak at gmail.com>

The intention here is to produce approximately the same number of samples for
each filter size (ie width*samples is the same). This means the caller can
pass a constant rather than a different value for each size. To avoid conflict
with existing code, negative numbers are used to indicate that -n samples are
needed at size==1.

The original idea was to scale n by 1/size, but experiments led to it being
scaled by 2/((size+1)*min(size,1)). This approaches twice as many samples as
size goes to either zero or infinity. For larger sizes this is scaling by the
width of a BOX.BOX filter, but for smaller size I don't have a good
explanation.

This function was arrived at experimentally by testing the scaling of the zone
plate image rotated slightly. The smallest number of samples that did not
produce more artifacts was plotted for various scales which led to the above
formula and a value of 12 for -n.

The computed value is then rounded up to the next power of 2 to get the
subsample_bits.

The scale demo is modified to allow these negative numbers, and initially
uses -12.

v11: Put subsample calculation in it's own function
     Minor changes to comments
v12: More info in the commit message
v13: Corrected mistakes in the commit message and comments about the scale factor

Signed-off-by: Bill Spitzak <spitzak at gmail.com>
Acked-by: Oded Gabbay <oded.gabbay at gmail.com>
---
 demos/scale.ui         |  5 +++--
 pixman/pixman-filter.c | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/demos/scale.ui b/demos/scale.ui
index b62cbfb..1e77f56 100644
--- a/demos/scale.ui
+++ b/demos/scale.ui
@@ -24,12 +24,12 @@
     <property name="page_size">10</property>
   </object>
   <object class="GtkAdjustment" id="subsample_adjustment">
-    <property name="lower">0</property>
+    <property name="lower">-256</property>
     <property name="upper">12</property>
     <property name="step_increment">1</property>
     <property name="page_increment">1</property>
     <property name="page_size">0</property>
-    <property name="value">4</property>
+    <property name="value">-12</property>
   </object>
   <object class="GtkWindow" id="main">
     <child>
@@ -321,6 +321,7 @@
                       <object class="GtkSpinButton" id="subsample_spin_button">
                         <property name="visible">True</property>
 			<property name="adjustment">subsample_adjustment</property>
+			<property name="value">-12</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 56e25b1..cb9f72b 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -346,6 +346,41 @@ filter_width (pixman_kernel_t reconstruct, pixman_kernel_t sample, double size)
     return ceil (filters[reconstruct].width + size * filters[sample].width);
 }
 
+/* Turn negative number into ceil(ln2(-n * 2/(size+1)*min(size,1)))
+ *
+ * The original idea was to scale n by 1/size, but experiments led to
+ * it being scaled by 2/((size+1)*min(size,1)). This approaches twice
+ * as many samples as size goes to either zero or infinity. For larger
+ * sizes this is scaling by the width of a BOX.BOX filter, but for
+ * smaller size I don't have a good explanation.
+ *    
+ * This function was arrived at experimentally by testing the scaling
+ * of the zone plate image rotated slightly. The smallest number of
+ * samples that did not produce more artifacts was plotted for various
+ * scales which led to the above formula and a value of 12 for -n.
+ */
+static int
+subsample_bits (int subsample_bits, pixman_kernel_t sample, double size)
+{
+    if (subsample_bits < 0)
+    {
+	double desired_samples = -subsample_bits;
+	if (sample == PIXMAN_KERNEL_IMPULSE)
+	    ; /* For x.IMPULSE no scaling is done */
+	else if (size >= 1.0)
+	    desired_samples *= 2.0 / (size + 1.0);
+	else
+	    desired_samples *= 2.0 / ((size + 1.0) * size);
+	if (desired_samples <= 1.0)
+	    subsample_bits = 0;
+	else if (desired_samples >= 256.0)
+	    subsample_bits = 8;
+	else
+	    subsample_bits = (int) ceil (log2(desired_samples) - .01);
+    }
+    return subsample_bits;
+}
+
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
  * with the given kernels and size parameters
  */
@@ -367,9 +402,11 @@ pixman_filter_create_separable_convolution (int             *n_values,
     int width, height;
 
     width = filter_width (reconstruct_x, sample_x, sx);
+    subsample_bits_x = subsample_bits (subsample_bits_x, sample_x, sx);
     subsample_x = (1 << subsample_bits_x);
 
     height = filter_width (reconstruct_y, sample_y, sy);
+    subsample_bits_y = subsample_bits (subsample_bits_y, sample_y, sy);
     subsample_y = (1 << subsample_bits_y);
 
     *n_values = 4 + width * subsample_x + height * subsample_y;
-- 
1.9.1



More information about the Pixman mailing list