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