RESOLVED FIXED 59764
Canvas: Use fast, approximate dirty rects for stroke()
https://bugs.webkit.org/show_bug.cgi?id=59764
Summary Canvas: Use fast, approximate dirty rects for stroke()
Andreas Kling
Reported 2011-04-28 17:35:30 PDT
Qt already has an optimization in place for CanvasRenderingContext2D::stroke() where we take the QPainterPath::controlPointRect() and grow it by the miterLimit and the lineWidth to create an approximate dirty rect which is significantly faster than rasterizing the path and calculating the exact bounding rect. We should share this optimization with other ports, using the inflated Path::boundingRect(), which is significantly faster on CG, and likely on other rendering libraries as well.
Attachments
Proposed patch (2.08 KB, patch)
2011-04-28 17:40 PDT, Andreas Kling
oliver: review+
Andreas Kling
Comment 1 2011-04-28 17:40:00 PDT
Created attachment 91606 [details] Proposed patch
Eric Seidel (no email)
Comment 2 2011-05-01 09:42:17 PDT
What perf test shows this change?
Oliver Hunt
Comment 3 2011-05-01 11:52:34 PDT
Comment on attachment 91606 [details] Proposed patch Does this handle acute angles with mitres correctly? I recall the the reason we didn't fix this in the past was due to potentially unbounded mitre size
Andreas Kling
Comment 4 2011-05-02 01:48:30 PDT
(In reply to comment #3) > What perf test shows this change? Spotted it on http://grantkot.com/sine.html which divides its rendering time between CGContextReplacePathWithStrokedPath (for bounding box calculation) and CGContextStrokePath (for actual rendering.) (In reply to comment #3) > Does this handle acute angles with mitres correctly? I recall the the reason we didn't fix this in the past was due to potentially unbounded mitre size How do you end up with an unbounded miter? The CanvasRenderingContext2D.miterLimit exists to prevent exactly that, no?
Matthew Delaney
Comment 5 2011-05-02 17:16:35 PDT
I believe Oliver is talking about the case where the user sets the miter limit to be huge and then has a very acute angle between two path segments and then strokes that path. Otherwise, here are a few others things I noticed. If we do end up not needing m_path.strokeBoundingRect, then we can likely get rid of it and also do the same alternative bounding rect calculation in the only other place this method (strokeBoundingRect) is used: RenderSVGPath.cpp. You mentioned it's significantly faster on CG - did you take down any performance measurements for any tests that would benefit from this? You mentioned the grantkot.com/sine.html page, but I don't see that that's a performance test. Did you instrument a local copy to get some FPS count for it or just notice that it was faster "to the eye"?
Andreas Kling
Comment 6 2011-05-05 06:42:25 PDT
(In reply to comment #5) > I believe Oliver is talking about the case where the user sets the miter limit to be huge and then has a very acute angle between two path segments and then strokes that path. Unless I'm misunderstanding something, that should be covered by the miterLimit property; if the stroke would extend outside the approximated rect, it would be drawn with a bevel join instead. > Otherwise, here are a few others things I noticed. If we do end up not needing m_path.strokeBoundingRect, then we can likely get rid of it and also do the same alternative bounding rect calculation in the only other place this method (strokeBoundingRect) is used: RenderSVGPath.cpp. RenderSVGPath needs the bounding rect to be correct, since it's used for more than invalidating the dirty region. > You mentioned it's significantly faster on CG - did you take down any performance measurements for any tests that would benefit from this? You mentioned the grantkot.com/sine.html page, but I don't see that that's a performance test. Did you instrument a local copy to get some FPS count for it or just notice that it was faster "to the eye"? I was playing around with a Mac for once, and wanted to try the "Instruments" application, so I ran this page through the time profiler tool. Like I said above, CPU time was (pretty much) equally divided by measuring the stroke and painting it. I could whip up a reduction with some human-friendly output if you like. :)
Brent Fulgham
Comment 7 2011-07-10 19:48:58 PDT
This has been sitting here for a couple of months, and seems like a good idea. Can we move this along somehow? Ollie -- are your concerns addressed by Andreas' responses?
Oliver Hunt
Comment 8 2011-07-11 09:00:51 PDT
(In reply to comment #6) > (In reply to comment #5) > > I believe Oliver is talking about the case where the user sets the miter limit to be huge and then has a very acute angle between two path segments and then strokes that path. > > Unless I'm misunderstanding something, that should be covered by the miterLimit property; if the stroke would extend outside the approximated rect, it would be drawn with a bevel join instead. > What's the default miterLimit? to my knowledge by default there is no limit...
Nikolas Zimmermann
Comment 9 2011-07-11 09:12:12 PDT
(In reply to comment #8) > (In reply to comment #6) > > (In reply to comment #5) > > > I believe Oliver is talking about the case where the user sets the miter limit to be huge and then has a very acute angle between two path segments and then strokes that path. > > > > Unless I'm misunderstanding something, that should be covered by the miterLimit property; if the stroke would extend outside the approximated rect, it would be drawn with a bevel join instead. > > > > What's the default miterLimit? to my knowledge by default there is no limit... In SVG the default miterLimit is 4.
Andreas Kling
Comment 10 2011-07-11 09:35:52 PDT
(In reply to comment #8) > (In reply to comment #6) > > (In reply to comment #5) > > > I believe Oliver is talking about the case where the user sets the miter limit to be huge and then has a very acute angle between two path segments and then strokes that path. > > > > Unless I'm misunderstanding something, that should be covered by the miterLimit property; if the stroke would extend outside the approximated rect, it would be drawn with a bevel join instead. > > > > What's the default miterLimit? to my knowledge by default there is no limit... The 2d canvas context has a default miterLimit of 10. ( http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-miterlimit )
Oliver Hunt
Comment 11 2011-07-11 09:39:00 PDT
Comment on attachment 91606 [details] Proposed patch r=me
Andreas Kling
Comment 12 2011-07-11 09:48:03 PDT
Note You need to log in before you can comment on or make changes to this bug.