[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-2d-dev
Subject:    [OpenJDK 2D-Dev] [10] RFR JDK-8191814: Marlin rasterizer spends time computing geometry for stroked 
From:       Laurent_Bourgès <bourges.laurent () gmail ! com>
Date:       2017-11-29 22:30:39
Message-ID: CAKjRUT7fX9rCb8nQX=KJ1=JGZft_GKPCkvY9HCOFS9BtHvahTg () mail ! gmail ! com
[Download RAW message or body]

Hi,

Please review this webrev of the Marlin renderer 0.8.2 for JDK-10
(jdk/client forrest). It provides an efficient path clipper in both Stroker
(float / double variants) & Filler fixing the bug JDK-8191814
<https://bugs.openjdk.java.net/browse/JDK-8191814>
I worked hard on this release since august and several patches were already
proposed 0.8.0 (Stroker only clipping) ... and discussed here:
http://mail.openjdk.java.net/pipermail/2d-dev/2017-August/008509.html

Bug: https://bugs.openjdk.java.net/browse/JDK-8191814
Webrev: http://cr.openjdk.java.net/~lbourges/marlin/marlin-082-8191814.0/

Build + tests: OK (see the new jtreg ClipShapeTest)

(I hope to provide the same upgrade to OpenJFX10 once this patch is
reviewed)

Detailled change log:
JDK-8191814

Marlin 0.8.2 changelog:
- (D)Curve: corrected computation of curve coefficients to minimize error
(stable formula)
- (D)Dasher:
    - lots of syntax changes
    - goTo(): use new method goTo_starting() to put slow path in another
method (hotspot)
    - lineTo() / somethingTo(): use local variables in loops for higher
efficiency
- (D)Helpers:
    - removed imports of Math functions (inlined in cubicRootsInAB)
    - removed unused polyLineLength()
    - added outcode() copied from GeneralRenderer
    - moved PolyStack class from (D)Stroker + use given Stat classes in
constructor
    - added new IndexStack class to store 'corner' (integer) indices for
the new PathClipFilter (Filler case): see push() that removes redundant
corners (direction flip) and pullAll() that returns the corner points from
all stored indices
- (D)MarlinRenderingEngine:
    - added new clip settings (doClip / doClipRuntimeFlag)
    - strokeTo(): added trace wrapper (disabled) and detectClosedPath() to
know in advance if the path is closed and properly handle caps for filled
polylines
    - getAATileGenerator(): define the initial clip bounds for both Stroker
/ Filler cases + use the new PathClipFilter (Filler case)
- (D)Renderer:
    - added constant for subpixel offsets (used to adjust the effective
clipping area)
    - moveTo() / lineTo() / quadTo() / curveTo() : renamed arguments
    - closePath(): skip useless addLine() call if P0 = S0
- (D)RendererContext: added clipping state: doClip & closedPath flags,
clipRect area (ymin, ymax, xmin, xmax) + increased array cache capacities
for new [Poly/Index]Stack instances

- (D)Stroker:
Approach: ignore outside segments (moveTo) without computing intersections
ie it opens the path (polyline) so extra care is needed to properly handle
visible cap (and joins).
    - fixed constants (CAP / JOIN) moved into MarlinConst
    - fixed PolyStack usage (moved into (D)Helper)
    - added clipping state (current / starting outcodes, opened / capStart
flags)
    - init(): adjust the clipping rectangle with the stroker margin (miter
limit, width) and (scaled) renderer offsets (if delta transformation in use)
    - moveTo(): finish() the current opened subpath + compute starting &
current outcode
    - lineTo() / quadTo() / curveTo() : added clipping = trivial segment
rejection based on point outcodes that 'opens' the path and calls moveTo()
    - closePath(): tricky (but tested) changes to emit moveTo() or lineTo()
if the closing segment is visible or not (and joins) + only emit close if
the path is inside
    - finish(): if ClosedPathDetector indicated the path is not closed: use
the outcode argument (current point) to only emit visible end cap and
visible start cap (starting outcode)
    - drawJoin(): added outcode argument (current point) to only emit
visible round / miter joins

- (D)TransformingPathConsumer2D:
    - moved all fields at the beginning
    - added ClosedPathDetector, PathClipFilter, PathTracer instances and
wrappers
    - deltaTransformConsumer(): adjust clip rectangle to deal with Stroker
coordinate transformations on the clipping area (inverse transform)
    - adjustClipInverseDelta(): for the shear transformation, the clipping
area is set to the bounding box (rectangle) of the 4 transformed points of
the initial clipping area
    - added the ClosedPathDetector class: simply set rdrCtx.closedPath to
true in closePath()
    - added the PathClipFilter class: (Filler case)
        Approach: clipping closed polygons is more complex than Stroker
(opened paths) to ignore outside segments but maintain the polygon closed
i.e. insert corner points (on the clip boundary) when an outside segment
crosses regions (T / L / B / R)
        - init(): adjust the clipping rectangle with the renderer offsets
        - finishPath(): totally ignore the path if the accumulated outcode
is outside
        - finish(): initialize corner points (if needed) and use the index
stack to emit all stored corners before emitting lineTo() to the current
point
        - closePath() / pathDone(): use finishPath() to emit remaining
points
        - moveTo(): initialize clipping state (outcodes, outside)
        - lineTo() / quadTo() / curveTo() : added clipping = trivial
segment rejection based on point outcodes and calls clip() to insert corner
points if needed + update the accumulated outcode (for finishPath)
        - clip(): tricky (but tested) solution to insert 1 or 2 corner
points in the index stack when the segment outcodes are different but only
on left or right sides
    - added the PathTracer class that log PathConsumer2D methods (std out)

- MarlinCache: fixed syntax of the useRLE flag (shorter conditions)
- MarlinConst: moved all WIND / CAP / JOIN constants here + added outcode
constants (sides & masks)
- MarlinProperties: added system properties for clipping
- RendererStats: updated statistics for new features
- Version: updated version to "marlin-0.8.2-Unsafe-OpenJDK"

- added new ClipShapeTest (jtreg) that checks all possible combinations of
(cap / join) for random polyline (Stroker) and polygons (Filler) comparing
image outputs rendered with clipping enabled vs disabled

Thanks for your time,

Cheers,
Laurent Bourgès

[Attachment #3 (text/html)]

<div dir="ltr"><div><div><div><div>Hi,<br><br></div>Please review this webrev of the \
Marlin renderer 0.8.2 for JDK-10 (jdk/client forrest). It provides an efficient path \
clipper in both Stroker (float / double variants) &amp; Filler fixing the bug <a \
class="gmail-issue-link" href="https://bugs.openjdk.java.net/browse/JDK-8191814" \
id="gmail-key-val" rel="4945424">JDK-8191814</a><br></div><div></div><div>I worked \
hard on this release since august and several patches were already proposed 0.8.0 \
(Stroker only clipping) ... and discussed here: <a \
href="http://mail.openjdk.java.net/pipermail/2d-dev/2017-August/008509.html">http://ma \
il.openjdk.java.net/pipermail/2d-dev/2017-August/008509.html</a><br></div><div><br>Bug: \
<a href="https://bugs.openjdk.java.net/browse/JDK-8191814">https://bugs.openjdk.java.net/browse/JDK-8191814</a><br>Webrev: \
<a href="http://cr.openjdk.java.net/~lbourges/marlin/marlin-082-8191814.0/">http://cr. \
openjdk.java.net/~lbourges/marlin/marlin-082-8191814.0/</a><br><br></div></div><div>Build \
+ tests: OK (see the new jtreg ClipShapeTest)</div><div><br></div><div>(I hope to \
provide the same upgrade to OpenJFX10 once this patch is \
reviewed)</div><div><br></div>Detailled change log:<br>JDK-8191814<br><br>Marlin \
0.8.2 changelog:<br>- (D)Curve: corrected computation of curve coefficients to \
minimize error (stable formula)<br>- (D)Dasher: <br>       - lots of syntax \
changes<br>       - goTo(): use new method goTo_starting() to put slow path in \
another method (hotspot)<br>       - lineTo() / somethingTo(): use local variables in \
loops for higher efficiency<br>- (D)Helpers:<br>       - removed imports of Math \
functions (inlined in cubicRootsInAB)<br>       - removed unused polyLineLength()<br> \
- added outcode() copied from GeneralRenderer<br>       - moved PolyStack class from \
(D)Stroker + use given Stat classes in constructor<br>       - added new IndexStack \
class to store &#39;corner&#39; (integer) indices for the new PathClipFilter (Filler \
case): see push() that removes redundant corners (direction flip) and pullAll() that \
returns the corner points from all stored indices<br>- (D)MarlinRenderingEngine:<br>  \
- added new clip settings (doClip / doClipRuntimeFlag)<br>       - strokeTo(): added \
trace wrapper (disabled) and detectClosedPath() to know in advance if the path is \
closed and properly handle caps for filled polylines<br>       - \
getAATileGenerator(): define the initial clip bounds for both Stroker / Filler cases \
+ use the new PathClipFilter (Filler case)<br>- (D)Renderer: <br>       - added \
constant for subpixel offsets (used to adjust the effective clipping area)<br>       \
- moveTo() / lineTo() / quadTo() / curveTo() : renamed arguments<br>       - \
closePath(): skip useless addLine() call if P0 = S0<br>- (D)RendererContext: added \
clipping state: doClip &amp; closedPath flags, clipRect area (ymin, ymax, xmin, xmax) \
+ increased array cache capacities for new [Poly/Index]Stack instances<br><br>- \
(D)Stroker: <br>Approach: ignore outside segments (moveTo) without computing \
intersections ie it opens the path (polyline) so extra care is needed to properly \
handle visible cap (and joins).<br>       - fixed constants (CAP / JOIN) moved into \
MarlinConst<br>       - fixed PolyStack usage (moved into (D)Helper)<br>       - \
added clipping state (current / starting outcodes, opened / capStart flags) <br>      \
- init(): adjust the clipping rectangle with the stroker margin (miter limit, width) \
and (scaled) renderer offsets (if delta transformation in use)<br>       - moveTo(): \
finish() the current opened subpath + compute starting &amp; current outcode<br>      \
- lineTo() / quadTo() / curveTo() : added clipping = trivial segment rejection based \
on point outcodes that &#39;opens&#39; the path and calls moveTo()<br>       - \
closePath(): tricky (but tested) changes to emit moveTo() or lineTo() if the closing \
segment is visible or not (and joins) + only emit close if the path is inside<br>     \
- finish(): if ClosedPathDetector indicated the path is not closed: use the outcode \
argument (current point) to only emit visible end cap and visible start cap (starting \
outcode)<br>       - drawJoin(): added outcode argument (current point) to only emit \
visible round / miter joins<br><br>- (D)TransformingPathConsumer2D: <br>       - \
moved all fields at the beginning<br>       - added ClosedPathDetector, \
PathClipFilter, PathTracer instances and wrappers<br>       - \
deltaTransformConsumer(): adjust clip rectangle to deal with Stroker coordinate \
transformations on the clipping area (inverse transform)<br>       - \
adjustClipInverseDelta(): for the shear transformation, the clipping area is set to \
the bounding box (rectangle) of the 4 transformed points of the initial clipping \
area<br>       - added the ClosedPathDetector class: simply set rdrCtx.closedPath to \
true in closePath()<br>       - added the PathClipFilter class: (Filler case)<br>     \
Approach: clipping closed polygons is more complex than Stroker (opened paths) to \
ignore outside segments but maintain the polygon closed i.e. insert corner points (on \
the clip boundary) when an outside segment crosses regions (T / L / B / R)<br>        \
- init(): adjust the clipping rectangle with the renderer offsets<br>               - \
finishPath(): totally ignore the path if the accumulated outcode is outside<br>       \
- finish(): initialize corner points (if needed) and use the index stack to emit all \
stored corners before emitting lineTo() to the current point<br>               - \
closePath() / pathDone(): use finishPath() to emit remaining points<br>               \
- moveTo(): initialize clipping state (outcodes, outside)<br>               - \
lineTo() / quadTo() / curveTo() : added clipping = trivial segment rejection based on \
point outcodes and calls clip() to insert corner points if needed + update the \
accumulated outcode (for finishPath)<br>               - clip(): tricky (but tested) \
solution to insert 1 or 2 corner points in the index stack when the segment outcodes \
are different but only on left or right sides<br>       - added the PathTracer class \
that log PathConsumer2D methods (std out)<br><br>- MarlinCache: fixed syntax of the \
useRLE flag (shorter conditions)<br>- MarlinConst: moved all WIND / CAP / JOIN \
constants here + added outcode constants (sides &amp; masks)<br>- MarlinProperties: \
added system properties for clipping<br>- RendererStats: updated statistics for new \
features<br>- Version: updated version to \
&quot;marlin-0.8.2-Unsafe-OpenJDK&quot;<br><br>- added new ClipShapeTest (jtreg) that \
checks all possible combinations of (cap / join) for random polyline (Stroker) and \
polygons (Filler) comparing image outputs rendered with clipping enabled vs \
disabled<br><br></div>Thanks for your time,<br><div><br \
clear="all"><div><div><div><div>Cheers,</div><div>Laurent Bourgès \
</div></div></div></div></div></div>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic