<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>