-
-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fast polygon scanning with active edge list #96
Conversation
// | Method | TextIterations | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | | ||
// |-------------- |--------------- |-------------:|-----------:|-----------:|-------:|--------:|----------:|---------:|------:|----------:| | ||
// | SystemDrawing | 1 | 55.03 us | 0.199 us | 0.186 us | 5.43 | 0.03 | - | - | - | 40 B | | ||
// | ImageSharp | 1 | 2,161.92 us | 4.203 us | 3.510 us | 213.14 | 0.52 | 253.9063 | - | - | 804452 B | | ||
// | SkiaSharp | 1 | 10.14 us | 0.040 us | 0.031 us | 1.00 | 0.00 | 0.5341 | - | - | 1680 B | | ||
// | | | | | | | | | | | | | ||
// | SystemDrawing | 20 | 1,450.12 us | 3.583 us | 3.176 us | 27.36 | 0.11 | - | - | - | 3696 B | | ||
// | ImageSharp | 20 | 28,559.17 us | 244.615 us | 216.844 us | 538.85 | 3.98 | 2312.5000 | 781.2500 | - | 9509056 B | | ||
// | SkiaSharp | 20 | 53.00 us | 0.166 us | 0.147 us | 1.00 | 0.00 | 1.6479 | - | - | 5336 B | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I'm doing something wrong in this benchmark, we are still a lot behind when it comes to draw text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... Anything obvious when profiling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code is same as with FillRegion
. I suppose GDI and Skia are utilizing some further optimizations for text rendering. Probably a global rasterized glyph cache? (This could be good candidate for LRU caching!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only thing I can see is the fact we don't seem have any need at all for any for the OrientationHandling
logic which leaves us with additional maintenance.
public static TessellatedMultipolygon Create( | ||
IPath path, | ||
MemoryAllocator memoryAllocator, | ||
OrientationHandling orientationHandling = OrientationHandling.ForcePositiveOrientationOnSimplePolygons) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ForcePositiveOrientationOnSimplePolygons
ends up not actually influencing the algorithm do we need the extra complexity of the other types seeing as none of our library code uses anything but this option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wanted to keep the flexibility to change this later if we want. Also: having the 3 options kinda documents what are we doing here and why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It all looks good to me, just a few questions really. I'll leave @tocsoft to do final approval as he actually understands this stuff! 😝
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very happy!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed everything's looking good.... still not 100% convinced we want the extra (unused) logic in TessellatedMultipolygon
but I'm happy to approve anyway. But I agree there is some follow up clean up actions to remove some unused/wanted codepaths, pretty much all of internal path can probably be dropped along with the more generic point in polygon/intersection logic etc from the paths.
@tocsoft I will remove the |
4ac3523
@tocsoft all done, I'm letting you have a final look and/or merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
approved 👍 nice work
Prerequisites
Summary
This PR is intended to narrow the performance gap we have compared to other frameworks by implementing the algorithm described in #90.
The PR is WIP, opened it to get early feedback. Remaining tasks:NonZero
intersection rule inPolygonScanner
PolygonScanner
inDrawTextProcessor
DrawTextProcessor
/FillRegionProcessor
codeTessellatedMultipolygon
orientation, and make sure the algorithm renders more or less nice output with CCW outermost contours + CW holes (see Fast polygon scanning with active edge list #96 (comment))ShapeOptions.UsePolygonScanner
)Implementation
IShape
->TesselatedMultipolygon
->ScanEdgeCollection
(compact representation of scannable edges) ->PolygonScanner
y
coordinates are rounded to the scanlines. This allows easy handling of corner cases. See NumericCornerCases.jpgScanEdgeCollection
. A line counts as horizontal by definition, if the whole line lies on the same scanline after rounding it'sy
coordinates.Results
Fixes #90 fixes #61 fixes #18.
Resolves #5 without offsetting the whole polygon, instead the calculation of coefficients in
ScanEdge
is centered around zero.According to my visual observation, the new algorithm has fewer robustness issues now. I suspect the remaining ones are caused by an unhandled corner case rather than by numeric issue:
Performance
The performance gains scale with the number of points in the polygon to draw. (
~8.5x
speedup filling Utah's and~62x
speedup filling Missisippi's polygons.)