[OpenJDK 2D-Dev] X11 uniform scaled wide lines and dashed lines; STROKE_CONTROL in Pisces
dlila at redhat.com
Fri Oct 8 08:53:43 PDT 2010
Sorry for all the e-mails, but I made a couple of other
notable changes I should mention.
1. The optimization I described in one of my other e-mails that
allowed Renderer to skip subdivision of curves into monotonic
pieces if the curves came from Stroker is gone. There was a bug
with round joins and caps (the curves composing them would not be
monotonic). I could have fixed this, but there's also the problem
that the rest of Stroker's output curves can only be guaranteed to
be monotonic in x and y if we can find all points in the non-offset
curve where the radius of curvature == linewidth. My algorithm that
tries to find these points does so pretty well, but it doesn't always
find them all.
2. I changed how the alpha map is managed in PiscesTileGenerator to
something that's a bit clearer and uses less memory (the latter comes
from changing the +300 in the alpha tile allocation to +1. If there was
a good reason for using 300, please tell me).
----- "Jim Graham" <james.graham at oracle.com> wrote:
> Hi Denis,
> On 9/27/2010 7:43 AM, Denis Lila wrote:
> > Hi Jim.
> >> How much faster? I'm worried about this, especially given our
> >> approach to requesting the data. What was the bottleneck before?
> >> (It's been a while since I visited the code - we weren't computing
> >> crossings for every curve in the path for every tile being
> >> were we?)
> > Not much faster. I'm working on someting better.
> Then hopefully we can get to something with better memory and CPU
> > I'm not sure about the bottleneck, but what we were doing
> before is:
> > 1. Flatten (by subdividing) every curve so that we deal only with
> > 2. Add each line to a list sorted by y0. When end_rendering was
> > for each scanline we found the crossings of the scanline and every
> > in our line list, which we used to compute the alpha for that
> > pixel row. All this would be put into RLE encoded temporary storage
> and it
> > would be read back and converted into tile form by
> > Speaking of which, would it not be better to get rid of
> PiscesCache and
> > just keep a buffer with the current tile row in Renderer.java. This
> > be possible because the specification for AATileGenerator says the
> > is like: for (y...) for (x...);.
> > Why is PiscesCache there? It isn't being used as a cache at all.
> Could it be?
> > Also, why do we output tiles, instead of just pixel rows (which I
> guess would
> > just be nx1 tiles). Is it because we would like to use
> getTypicalAlpha to eliminate
> > completely transparent or completely opaque regions as soon as
> possible (and the
> > longer a tile is the less of a chance it has at being either of
> those two)?
> That was basically "cramming what we had into the interface's box".
> cache existed for something that was being done on mobile, but it
> doesn't have much of a place in our APIs so it was just reused for
> generation. If we have a much more direct way of doing it then it
> be great to get rid of it.
> I think we can support "ALL1s" and "ALL0s" reasonably without the
> >> I can see your points here. I think there are solutions to avoid
> >> of the untransforming we can consider, but your solution works well
> >> let's get it in and then we can look at optimizations if we feel
> >> are causing a measurable problem later.
> > I should say this isn't quite as bad as I might have made it
> seem. Firstly,
> > this IO handler class I made elimiinates transformations when
> > communicates with Stroker. More importantly, no untransforming is
> > when the transformation is just a translation or is the identity or
> is singular
> > and when STROKE_CONTROL is off, we only transform the output path.
> > because the most important reason for handling transforms the way I
> do now
> > is because we can't normalize untransformed paths, otherwise
> > adjustments might be magnified too much. So, we need to transform
> > before normalization. But we also can't do the stroking and
> > before the normalization. But if normalization is removed we can
> just pass
> > untransformed paths into Stroker, and transform its output (which is
> > somewhat more expensive than only trasnforming the input path,
> > Stroker produces many 3-7 curves for each input curve).
> Can the untransform be eliminated in the case of scaling? (Whether
> for uniform scaling, or maybe even for non-uniform scaling with no
> rotation or shearing?)
> >> I'm not sure I understand the reasoning of the control point
> >> calculation. I'll have to look at the code to register an
> > I'm sorry, my explanation wasn't very clear. I attached a
> picture that
> > will hopefully clarify things.
> > But, in a way, the computation I use is forced on us. Suppose we
> have a
> > quadratic curve B and we need to compute one of its offsets C.
> > and C'(1) will be parallel to B'(0) and B'(1) so we need to make
> > our computed offset has this property too (or it would look weird
> > the endpoints). Now, B'(0) and B'(1) are parallel to p2-p1 and
> > where p1,p2,p3 are the 3 control points that define B, so if the
> > points of C are q1, q2, q3 then q2-q1 and q3-q2 must be parallel to
> > and p3-p2 respectively. At this point, we need more constraint,
> > our system is underdetermined. We use the constraints that q1 =
> > and q3 = C(1) (so, the endpoints of the computed offset are equal to
> > endpoints of the ideal offset). All we have left to compute is q2,
> > we know the direction of q2-q1 and the direction of q3-q2, so q2
> > lie on the lines defined by q1+t*(q2-q1) and q3+t*(q3-q2) so q2
> > be the intersection of these lines.
> I agree that if you are creating a parallel curve then intersection is
> the way to go. I guess what I was potentially confused about was
> whether there are cases where you need to subdivide at all?
> of subdivision, when you get down to the final step of creating the
> parallel curves then I believe offsetting and finding the intersection
> is correct (though I reserve the possibility that there might still be
> simpler way - I haven't done any investigation to know if that is
> >> It sounds like you are correct here. What does the closed source
> >> draw?
> > I thought closed source java simply didn't draw the round joins
> > these cases, but I did some more testing and it turns out it does
> > some curves and it doesn't for others. I've included the results of
> > test I wrote that tries to draw paths like:
> > where cos and sin are coordinates on a circle (source1.png is the
> > of closed java. Source2.png is my output). As you can see, my
> > version draws the round joins on all tested cases, while closed
> > is inconsistent.
> You rock then! A bug should be filed on closed JDK. Can you file it
> send me your test case and I'll do it?
> > That sounds good. Hopefully by the end of today I'll have a
> > less memory hungry AA implementation that is also faster.
> > Thank you,
> Ummm... Thank *you*. You're doing all the good work here, I'm just
> sitting back, throwing out tiny crumbs of past experience and watching
> the ensuing woodchips fly with awe. I've had on my wish list for some
> time to be able to eliminate these last few closed source holdouts,
> the quality of the Ductus code was so high that I never got motivated
> try. Who knows now... ;-)
More information about the 2d-dev