<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Apr 11, 2016 at 7:36 PM, Søren Sandmann Pedersen <span dir="ltr"><<a href="mailto:soren.sandmann@gmail.com" target="_blank">soren.sandmann@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Bill Spitzak <<a href="mailto:spitzak@gmail.com">spitzak@gmail.com</a>><br>
<br>
If enable-gnuplot is configured, then you can pipe the output of a<br>
pixman-using program to gnuplot and get a continuously-updated plot of<br>
the horizontal filter. This works well with demos/scale to test the<br>
filter generation.<br>
<br>
The plot is all the different subposition filters shuffled<br>
together. This is misleading in a few cases:<br>
<br>
  IMPULSE.BOX - goes up and down as the subfilters have different<br>
                numbers of non-zero samples<br>
<br>
  IMPULSE.TRIANGLE - somewhat crooked for the same reason<br>
<br>
  1-wide filters - looks triangular, but a 1-wide box would be more<br>
                   accurate<br></blockquote><div><br></div><div>Because you are not plotting the two dummy points at (0,±width/2), a 1-wide filter is actually just a single point.</div><div><br></div><div>You may be right that leaving the dummy points off the plot may make it easier to figure out what is going on.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Changes by Søren: Rewrote the pixman-filter.c part to<br>
     - make it generate correct coordinates<br>
     - add a comment on how coordinates are generated<br>
     - in rounding.txt, add a ceil() variant of the first-sample<br>
       formula<br>
     - make the gnuplot output slightly prettier<br>
<br>
v7: First time this ability was included<br>
<br>
v8: Use config option<br>
    Moved code to the filter generator<br>
    Modified scale demo to not call filter generator a second time.<br>
<br>
v10: Only print if successful generation of plots<br>
     Use #ifdef, not #if<br>
<br>
v11: small whitespace fixes<br>
<br>
Signed-off-by: Bill Spitzak <<a href="mailto:spitzak@gmail.com">spitzak@gmail.com</a>><br>
Signed-off-by: Søren Sandmann <<a href="mailto:soren.sandmann@gmail.com">soren.sandmann@gmail.com</a>><br>
---<br>
 <a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a>           |  13 ++++++<br>
 pixman/pixman-filter.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++<br>
 pixman/rounding.txt    |   1 +<br>
 3 files changed, 129 insertions(+)<br>
<br>
diff --git a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a> b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
index 6b2134e..e833e45 100644<br>
--- a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
+++ b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
@@ -834,6 +834,19 @@ fi<br>
 AC_SUBST(PIXMAN_TIMERS)<br>
<br>
 dnl ===================================<br>
+dnl gnuplot<br>
+<br>
+AC_ARG_ENABLE(gnuplot,<br>
+   [AC_HELP_STRING([--enable-gnuplot],<br>
+                   [enable output of filters that can be piped to gnuplot [default=no]])],<br>
+   [enable_gnuplot=$enableval], [enable_gnuplot=no])<br>
+<br>
+if test $enable_gnuplot = yes ; then<br>
+   AC_DEFINE(PIXMAN_GNUPLOT, 1, [enable output that can be piped to gnuplot])<br>
+fi<br>
+AC_SUBST(PIXMAN_GNUPLOT)<br>
+<br>
+dnl ===================================<br>
 dnl GTK+<br>
<br>
 AC_ARG_ENABLE(gtk,<br>
diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c<br>
index b2bf53f..af46a43 100644<br>
--- a/pixman/pixman-filter.c<br>
+++ b/pixman/pixman-filter.c<br>
@@ -297,6 +297,117 @@ create_1d_filter (int             *width,<br>
     return params;<br>
 }<br>
<br>
+#ifdef PIXMAN_GNUPLOT<br>
+<br>
+/* If enable-gnuplot is configured, then you can pipe the output of a<br>
+ * pixman-using program to gnuplot and get a continuously-updated plot<br>
+ * of the horizontal filter. This works well with demos/scale to test<br>
+ * the filter generation.<br>
+ *<br>
+ * The plot is all the different subposition filters shuffled<br>
+ * together. This is misleading in a few cases:<br>
+ *<br>
+ *  IMPULSE.BOX - goes up and down as the subfilters have different<br>
+ *               numbers of non-zero samples<br>
+ *  IMPULSE.TRIANGLE - somewhat crooked for the same reason<br>
+ *  1-wide filters - looks triangular, but a 1-wide box would be more<br>
+ *                  accurate<br>
+ */<br>
+static void<br>
+gnuplot_filter (int width, int n_phases, const pixman_fixed_t* p)<br>
+{<br>
+    double step;<br>
+    int i, j;<br>
+    int first;<br>
+<br>
+    step = 1.0 / n_phases;<br>
+<br>
+    printf ("set style line 1 lc rgb '#0060ad' lt 1 lw 0.5 pt 7 pi 1 ps 0.5\n");<br>
+    printf ("plot '-' with linespoints ls 1\n");<br>
+<br>
+    /* The position of the first sample of the phase corresponding to<br>
+     * frac is given by:<br>
+     *<br>
+     *     ceil (frac - width / 2.0 - 0.5) + 0.5 - frac<br>
+     *<br>
+     * We have to find the frac that minimizes this expression.<br>
+     *<br>
+     * For odd widths, we have<br>
+     *<br>
+     *     ceil (frac - width / 2.0 - 0.5) + 0.5 - frac<br>
+     *   = ceil (frac) + K - frac<br>
+     *   = 1 + K - frac<br>
+     *<br>
+     * for some K, so this is minimized when frac is maximized and<br>
+     * strictly growing with frac. So for odd widths, we can simply<br>
+     * start at the last phase and go backwards.<br>
+     *<br>
+     * For even widths, we have<br>
+     *<br>
+     *     ceil (frac - width / 2.0 - 0.5) + 0.5 - frac<br>
+     *   = ceil (frac - 0.5) + K - frac<br>
+     *<br>
+     * The graph for this function (ignoring K) looks like this:<br>
+     *<br>
+     *        0.5<br>
+     *           |    |\<br>
+     *           |    | \<br>
+     *           |    |  \<br>
+     *         0 |    |   \<br>
+     *           |\   |<br>
+     *           | \  |<br>
+     *           |  \ |<br>
+     *      -0.5 |   \|<br>
+     *   ---------------------------------<br>
+     *           0    0.5   1<br>
+     *<br>
+     * So in this case we need to start with the phase whose frac is<br>
+     * less than, but as close as possible to 0.5, then go backwards<br>
+     * until we hit the first phase, then wrap around to the last<br>
+     * phase and continue backwards.<br>
+     *<br>
+     * Which phase is as close as possible 0.5? The locations of the<br>
+     * sampling point corresponding to the kth phase is given by<br>
+     * 1/(2 * n_phases) + k / n_phases:<br>
+     *<br>
+     *         1/(2 * n_phases) + k / n_phases = 0.5<br>
+     *<br>
+     * from which it follows that<br>
+     *<br>
+     *         k = (n_phases - 1) / 2<br>
+     *<br>
+     * rounded down is the phase in question.<br>
+     */<br>
+    if (width & 1)<br>
+       first = n_phases - 1;<br>
+    else<br>
+       first = (n_phases - 1) / 2;<br></blockquote><div><br></div><div>My version printed an extra point at 0,-width/2 here. Not sure if that is an improvement or a bug, you might want to try it just to get your opinion.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    for (j = 0; j < width; ++j)<br>
+    {<br>
+       for (i = 0; i < n_phases; ++i)<br>
+       {<br>
+           int phase = first - i;<br>
+           double frac, pos;<br>
+<br>
+           if (phase < 0)<br>
+               phase = n_phases + phase;<br>
+<br>
+           frac = step / 2.0 + phase * step;<br>
+           pos = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac + j;<br></blockquote><div><br></div><div>See below I think this has to be changed to the floor() version.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+           printf ("%g %g\n",<br>
+                   pos,<br>
+                   pixman_fixed_to_double (*(p + phase * width + j)));<br>
+       }<br>
+    }<br></blockquote><div><br></div><div>My version printed an extra point at 0,width/2 here.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    printf ("e\n");<br>
+    fflush (stdout);<br>
+}<br>
+<br>
+#endif<br>
+<br>
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter<br>
  * with the given kernels and scale parameters<br>
  */<br>
@@ -346,5 +457,9 @@ out:<br>
     free (horz);<br>
     free (vert);<br>
<br>
+#ifdef PIXMAN_GNUPLOT<br>
+    gnuplot_filter(width, subsample_x, params + 4);<br>
+#endif<br>
+<br>
     return params;<br>
 }<br>
diff --git a/pixman/rounding.txt b/pixman/rounding.txt<br>
index b52b084..1c00019 100644<br>
--- a/pixman/rounding.txt<br>
+++ b/pixman/rounding.txt<br>
@@ -160,6 +160,7 @@ which means the contents of the matrix corresponding to (frac) should<br>
 contain width samplings of the function, with the first sample at:<br>
<br>
        floor (frac - (width - 1) / 2.0 - e) + 0.5 - frac<br>
+     = ceil (frac - width / 2.0 - 0.5) + 0.5 - frac<br></blockquote><div><br></div><div>Unfortunately this produces numbers that don't agree with the filter generator or filtering code.</div><div><br></div><div>For a width==4 filter with n_phases==1, the generator seems to produce values at -1, 0, 1, 2, so the first sample is at -1. It also appears the filtering sampler is using the same rule, otherwise these filters would produce an obvious shift in the image.</div><div><br></div><div>    frac = step/2 = .5</div><div>    width = 3</div><div>    floor (frac - (width - 1) / 2.0) + 0.5 - frac = floor(.5 - 1.5) + 0.5-0.5 = floor(-1) = -1.</div><div>    ceil (frac - width / 2.0 - 0.5) + 0.5 - frac = ceil(.5 - 2.5) + 0.5-0.5 = ceil(-2) = -2</div><div><br></div><div>Whether by accident or not it looks like the correct formula is the floor one with the epsilon (e) removed, in disagreement with your rounding.txt document. I would recommend using that rather than changing the interpretation of the filter matrix.</div><div><br></div></div><br></div></div>