[OpenJDK 2D-Dev] X11 uniform scaled wide lines and dashed lines; STROKE_CONTROL in Pisces

Jim Graham james.graham at oracle.com
Tue Oct 26 20:55:42 UTC 2010


On 10/26/2010 6:58 AM, Denis Lila wrote:
>> If we are really worried about the y-sort, then how about creating a
>> bunch of buckets and doing a bucket sort of the edges?  As they are
>> added to the list of segments, we accumulate their indices in a row
>> list based on their startY so that each step of the "next()" simply moves
>> to the next Y and adds the edges mentioned in the list there.  Some work
>> would have to be done on how to manage the storage simply (like a
>> "rownext" field in the edge structure so that they are linked in a
>> linked list), but then there would be no qsort at all for the cost of
>> new int[N_ROWS] and an extra field in every edge.
>
> I like this.

It's even more frugal if combined with my idea that an entire full pixel 
row could be processed in one batch rather than processing each 
sub-pixel row separately.

>> 90% (guesstimate) of the time edges do not cross each other, thus if
>> you sort the crossings without reordering the active edges then you just
>> end up doing the same sorting work (same swaps) on the next scanline.  My
>> SpanShapeIterator code actually reordered the edges on every sample
>> line to match their current X coordinates in a way that involved 1 compare
>> per edge that was processed and only occasionally a swap of 2 edge
>> pointers.  It would basically eliminate the sort at line 149 at the
>> cost of only doing a compare in the nextY processing for the very very
>> common case.
>
> I also implemented this some time ago. I didn't keep it because it slowed
> things down a bit. However, I only tested it with very complex and large
> paths, and in hindsight, I shouldn't have based my decision on that, so I
> will re-implement it.

First, this is less helpful if we process the edges/quads/curves in 3 
separate batches because you'd still have 3 sets of crossings to 
interweave and so some sorting would still be necessary, but keeping 
each of the 3 sets sorted amongst themselves might still help with 
reducing the swapping work of the sorting step.  This technique would 
work best if all of the edge types were processed from one list.

Also, be sure to test with both clockwise and couterclockwise versions 
of the test paths just in case.  The (constantly re)sorting hit will be 
more expensive with one than the other since one of them will have the 
edges already in the sorted order and the other would require maximum 
swaps.  I'd check:

Simple CW rectangle
Simple CCW rectangle
CW and CCW rectangles with 500(?) zig-zags along top edge
CW and CCW rectangles with 500(?) zig-zags along both top and bottom

And a note related to another suggestion I'd made, I think if we did 
something like "process an entire pixel row at once" it would complicate 
the "auto-edge sorting" a bit.  If every curve is iterated to the bottom 
of the pixel in turn before moving to the next edge then its crossings 
may swap with another edge's crossings, but that next edge would not be 
processed yet and then there may be a mish-mosh of N subpixel values 
from the two edges to interweave.  If it was done by processing each 
subpixel row in turn then the edges could be kept sorted as the subpixel 
rows were iterated, but it would reduce the savings on the overhead of 
swapping between edges.  The best compromise might be to process every 
curve fully, verify its sorted position in the edge array using its X 
coordinate at the bottom of the pixel, still sort the whole pixel row's 
worth of crossing values, but hopefully the sorting would have very 
little work to do if the original values were "mostly sorted" by having 
kept the edges in order at pixel boundaries (a "mostly sorted" friendly 
sort algorithm, like insertion sort, might be needed).

			...jim



More information about the 2d-dev mailing list