[OpenJDK 2D-Dev] RFR 8144938: Handle properly coordinate overflow in Marlin Renderer

Jim Graham james.graham at oracle.com
Mon Mar 14 23:34:48 UTC 2016


Hi Laurent,

Did you consider adding a test with a completely degenerate path to make 
sure that we don't have any state errors if all of the segments are 
eaten by the "finite path" filter?

I like your approach.  It is worth noting that:

- non-uniform scales are not common
- your "always overflow-filter path at device resolution" fixes the 
issues with measuring overflow in user space that I pointed out in my 
prior email and only does so at a likely small expense in terms of 
non-uniform scale performance.  Common cases will see no change (other 
than the fact that you have new code in the path feeder).

With respect to the optimization that I gave a rough outline of.  It is 
true that:

- it should help eliminate all of the inverse transforms in the strokeTo 
code
- the math is incomplete and would need some work
- it only targets the non-uniform case which may not be a high priority
- it would probably get rid of the entire TransformingPathConsumer 
module, but that module is not complex or trouble-prone and seems to be 
working fine

		...jim

On 3/11/2016 2:14 PM, Laurent Bourgès wrote:
> Jim,
>
> Here is a webrev illustrating my 'simple' approach:
> http://cr.openjdk.java.net/~lbourges/marlin/marlin-8144938.1/
>
> Changes:
> - MarlinRenderingEngine.strokeTo(): removed outat ie always call
> src.getPathIterator(at) that ensures Marlin is working in device-space
> coordinates; so pathTo() can filter out NaN / Infinity points
> - TransformingPathConsumer2D: removed transformConsumer() and all its
> related inner classes (simplification)
>
> I will perform a MapBench benchmark focused on non-uniform
> transformation to check the possible performance 'regression'.
>
> Please give me your point of view on the NaN/Infinity overflow handling
> that I think it is now correct as all path coordinates are in
> the device-space.
>
>
> I think you proposed an optimized approach to refine my solution and get
> rid of all inverseDelta/delta transformations at all, does it ?
>
> I am not sure to have understood all the maths here (after my first 2/3
> reads) but it seems quite complex and I am a bit reluctant as computing
> curve offsets or curved lengths seems to me very very tricky and
> error-prone !
>
> I think your advices are very interesting but I need more concrete
> directions to try making changes myself in the Stroker / Dasher code.
>
> What is the use case for non-uniform transformations ? how important is
> it ? In other words, is it worth such effort ?
>
>
>         Do you have an alternative solution (simple) ?
>
>
>     Yes, if we can take a non-uniform transform and express the pen size
>     as a tilted ellipse, then we can supply the tilted ellipse
>     parameters to the stroker and it could perform device-space widening
>     of non-uniform pens.  Basically, we have a method right now that
>     takes the dx,dy of a path and turns it into a unit vector, does a
>     simplistic 90 degree transform, and then scales it by the line
>     width.  It looks something like (adapted from Stroker.computeOffset()):
>
>     mdx =  dy / len(dx,dy) * halfwidth;
>     mdy = -dx / len(dx,dy) * halfwidth;
>
>     which is shorthand for:
>
>     (1) normalize dx,dy
>     (2) rotate dx,dy by 90 degrees
>     (3) multiply by half the transformed line width
>
>     What we'd need to do for the general case is:
>
>     (1) inverse delta transform to user space
>     (2) normalize dx,dy to unit vector
>     (3) rotate by 90 degrees
>     (4) scale by (half) user space line width
>     (5) transform back to device space
>
>
> I agree.
>
>     (1) and (3) through (5) are all 2x2 transforms and they could be
>     able to be flattened into a single transform, but we have that pesky
>     normalize step at (2) that gets in the way.  If not for that, we
>     could replace the contents of computeOffset with just a 2x2 matrix
>     multiply, but I punted when I looked at how to introduce the
>     normalization step.  I'm pretty sure that (1) and (2) could be
>     swapped somehow because all we really have is an elliptical pen and
>     we should be able to take a normalized vector in device space and
>     compute a transform that rotates it to the proper orientation that
>     comes from "inverseTx, rotate90, Tx" and applies the proper scale,
>     but how to compute that?  When done we'd just have a 2x2 matrix to
>     multiply by, but since the construction of that 2x2 matrix wasn't
>     immediately obvious from concatenating component matrices I punted
>     to other problems.
>
>
> A bit lost, but globally I understand. Probably some degenated cases may
> apperar (matrix inversion ?)
>
>     Another thing to consider is that dash length will vary based on
>     angle so we'd need a way to compute "user length of device dx,dy"
>     quickly. It's essentially computing "len(inverseTransform(dx,dy))",
>     which is:
>
>     udx = inverseMxx * dx + inverseMxy * dy;
>     udy = inverseMyx * dx + inverseMyy * dy;
>     return sqrt(udx * udx + udy * udy);
>
>     which is (renaming inverseM* to I*), and please check my math:
>
>     sqrt((Ixx * dx + Ixy * dy)^2 + (Iyx * dx + Iyy * dy)^2);
>     sqrt(Ixx*Ixx*dx*dx + 2Ixx*Ixy*dx*dy + Ixy*Ixy*dy*dy +
>           Iyx*Iyx*dx*dx + 2Iyx*Iyy*dx*dy + Iyy*Iyy*dy*dy);
>     sqrt( (Ixx*Ixx + Iyx*Iyx)*dx*dx +
>           2(Ixx*Ixy + Iyx*Iyy)*dx*dy +
>            (Ixy*Ixy + Iyy*Iyy)*dy*dy);
>     sqrt(K1 * dx * dx + K2 * dx * dy + K3 * dy * dy);
>
>
> Will check later (as it is late here) but it looks correct.
>
>
>     For a uniform scale K1 == K3 == squared inverse scale and K2 == 0
>     and K1,K3 can then be factored out of the sqrt into a constant and
>     applied to the dash lengths instead.
>
>     which is only a little more complicated than a regular length
>     computation.  Unfortunately, since the angle changes over the course
>     of a curve, it might prove a little tricky for the iterator that
>     computes the length of the dashes along the curve, but it could be
>     as simple as calling a different length method as it iterates.
>
>
> It seems too simple to be true. I have doubts I can handle such changes
> myself.
>
>         Besides, we should also check early if the transformation matrix
>         contains NaN or Infinity values avoiding the path iteration. I
>         advocate
>         it is an extreme case.
>
>
>     That could be a short-cut optimization, but it depends on how much
>     it costs compared to just letting the path degeneracy elimination
>     turn it all into a NOP segment by segment...
>
>
> I agree this shortcut is only worth if it happens in reality...
>
> To conclude tonight, I will run few benchmarks and am looking forward
> your comments.
>
> Cheers,
> Laurent



More information about the 2d-dev mailing list