[OpenJDK 2D-Dev] sun.java2D.pisces big memory usage & Dasher clipping problem

Jim Graham james.graham at oracle.com
Sat Mar 30 00:33:43 UTC 2013


J2DBench does not have a regression test mode unfortunately.

Clipping in the stroker and dasher is doable, but it is complicated by the fact that stroking adds decorations that are not always easy to account for.  Round joins and end caps are easy - they "grow" the path by exactly half the line width.  Square and Butt caps and Bevel joins are equally predictable, you can do some trig or come up with an upper bound on how much they may "grow" the path in any given direction.  Miter joins are the hardest as it depends on the miter limit and the angle between the line segments.  Also, curves could be rejected based on conservative trivial estimates of the worst case of the path and the worst case of the stroke "grow" factor by using their 4 control points, but if you want something more exact then you have to subdivide them anyway.

And when you cull, you have to remember to update all of the state so that you know the "previous slope and join info" so that the next segment, which might not be culled, can interpolate the correct joins.

As with any culling, you have to measure the likelihood of success against the cost of the computations.  As such, it is probably best to perform the most conservative estimates before culling the paths so that you don't slow down some common cases of the path being fully visible.

I forget how the Renderer piece is written, but hopefully it culls segments that are outside the clip so that while we may waste time generating the dashes and widened paths for parts that are outside the clip, at least we don't spend time rasterizing them?

			...jim

On 3/28/2013 8:40 AM, Laurent Bourgès wrote:
> Dear java2d members,
>
> FYI: I now have a working patched java2d pisces that performs better: no memory waste (99%) and performance increased on complex operations (dashed ...); patch / benchmark in progress ...
>
> Does J2DBench have a regression test mode ?
> i.e. capture screenshots (with few shapes) to compare them between different runs (image comparison pixel by pixel)
>
> Besides, I found an important bug in pisces Stroker / Dasher: it does not use the clip region given to PiscesRenderingEngine.getAATileGenerator(clip).
>
> In Aspro2, I can zoom on jFreeChart plots a lot and it draws shapes (rectangle or lines with dashed lines) then the dasher emits segments out of the visible area (millions in case of a important zoom) and the application hangs a for while (5s to minutes).
>
> I would like to determine the shape part (line or any complex shape) that is inside the clip and avoid useless segments (Stroker / Dasher).
>
> Does somebody have any idea ?
> or know java2d.pisces code enough to help me ?
>
> Laurent
>
>
> 2013/3/26 Laurent Bourgès <bourges.laurent at gmail.com <mailto:bourges.laurent at gmail.com>>
>
>     Dear all,
>
>     First I joined recently the openJDK contributors, and I plan to fix java2D pisces code in my spare time.
>
>     I have a full time job on Aspro2: http://www.jmmc.fr/aspro; it is an application to prepare astronomical observations at VLTI / CHARA and is very used in our community (200 users): it provides scientific computations (observability, model images using complex numbers ...) and zoomable plots thanks to jFreeChart.
>
>     Aspro2 is known to be very efficient (computation parallelization) and I am often doing profiling using netbeans profiler or visualVM.
>
>     To fix huge memory usages by java2d.pisces, I started implementing an efficient ArrayCache (int[] and float[]) (in thread local to concurrency problems):
>     - arrays in sizes between 10 and 10000 (more small arrays used than big ones)
>     - resizing support (Arrays.copyOf) without wasting arrays
>     - reentrance i.e. many arrays are used at the same time (java2D Pisces stroke / dash creates many segments to render)
>     - GC / Heap friendly ie support cache eviction and avoid consuming too much memory
>
>     I know object pooling is known to be not efficient with recent VM (GC is better) but I think it is counter productive to create so many int[] arrays in java2d.pisces and let the GC remove such wasted memory.
>
>     Does someone have implemented such (open source) array cache (core-libs) ?
>     Opinions are welcome (but avoid "trolls").
>
>     Moreover, sun.java2d.pisces.Helpers.widenArray() performs a lot of array resizing / copy (Arrays.copyOf) that I want to avoid mostly:
>          // These use a hardcoded factor of 2 for increasing sizes. Perhaps this
>          // should be provided as an argument.
>          static float[] widenArray(float[] in, final int cursize, final int numToAdd) {
>              if (in.length >= cursize + numToAdd) {
>                  return in;
>              }
>              return Arrays.copyOf(in, 2 * (cursize + numToAdd));
>          }
>
>          static int[] widenArray(int[] in, final int cursize, final int numToAdd) {
>              if (in.length >= cursize + numToAdd) {
>                  return in;
>              }
>              return Arrays.copyOf(in, 2 * (cursize + numToAdd));
>          }
>
>     Thanks to Peter Levart, I use its microbench tool (https://github.com/plevart/micro-bench/tree/v2) to benchmark ArrayCache operations... and J2DBench to test java2d performances
>
> ...
>
>
>     PS: java.awt.geom.Path2D has also memory allocation issues:
>              void needRoom(boolean needMove, int newCoords) {
>                  if (needMove && numTypes == 0) {
>                      throw new IllegalPathStateException("missing initial moveto "+
>                                                          "in path definition");
>                  }
>                  int size = pointTypes.length;
>                  if (numTypes >= size) {
>                      int grow = size;
>                      if (grow > EXPAND_MAX) {
>                          grow = EXPAND_MAX;
>                      }
>                      pointTypes = Arrays.copyOf(pointTypes, size+grow);
>                  }
>                  size = floatCoords.length;
>                  if (numCoords + newCoords > size) {
>                      int grow = size;
>                      if (grow > EXPAND_MAX * 2) {
>                          grow = EXPAND_MAX * 2;
>                      }
>                      if (grow < newCoords) {
>                          grow = newCoords;
>                      }
>                      floatCoords = Arrays.copyOf(floatCoords, size+grow);
>                  }
>              }
>
>     Best regards,
>     Laurent
>
>



More information about the 2d-dev mailing list