SkPath extremely slow to render on certain zoom levels

460 views
Skip to first unread message

Jean-Claude Monnin

unread,
Jul 5, 2020, 3:56:52 AM7/5/20
to skia-d...@googlegroups.com
Hi,

I have a path that takes a really long time to render depending on the zoom level. I can reproduce the problem on a linux system with an AMD card and different Android phones, but other configurations, like a machine with Nvidia card is not affected. The path is usually very quick to render; but when the view changes and triggers the problem, the rending time goes up dramatically (~1 sec to render on the AMD system and ~10 sec on Android phone).

"skp" file is attached. The WASM debugger (https://debugger.skia.org) doesn't reproduce the problem, but the locally built `skiaserve` does when using GPU (software mode is fine).

I'm using m83 and it has been built with:
gn gen out/Test --args='cc="clang" cxx="clang++" is_official_build=false skia_enable_tools=true'
ninja -C out/test/ skiaserve

Other build with ` is_official_build=true` and other options shows the issue too. I've initially was on m77 and I also tried m85, and they behave similarly. The application uses OpenGL rendering. See [1] for a typical stack trace of when the rendering is "stuck".

Any advice on what is going on and how to work around this issue would be welcome.

Thanks,
Jean-Claude




[1] Stack trace
-------------------
1 AlmostLessOrEqualUlps(float, float) 0x5555559711e5
2 AddIntersectTs(SkOpContour *, SkOpContour *, SkOpCoincidence *) 0x555555c92be1
3 OpDebug(SkPath const&, SkPath const&, SkPathOp, SkPath *) 0x555555b31dce
4 GrCoverageCountingPathRenderer::CropPath(SkPath const&, SkIRect const&, SkPath *) 0x555555a5f13f
5 GrCCDrawPathsOp::Make(GrRecordingContext *, SkIRect const&, SkMatrix const&, GrStyledShape const&, GrPaint&&) 0x555555c0e193
6 GrCoverageCountingPathRenderer::onDrawPath(GrPathRenderer::DrawPathArgs const&) 0x555555a5ec46
7 GrRenderTargetContext::drawShapeUsingPathRenderer(GrClip const *, GrPaint&&, GrAA, SkMatrix const&, GrStyledShape const&, bool) 0x5555559b7fcb
8 GrRenderTargetContext::drawShape(GrClip const *, GrPaint&&, GrAA, SkMatrix const&, GrStyledShape const&) 0x5555559bfde8
9 GrRenderTargetContext::drawPath(GrClip const *, GrPaint&&, GrAA, SkMatrix const&, SkPath const&, GrStyle const&) 0x5555559bb001
10 SkGpuDevice::drawPath(SkPath const&, SkPaint const&, bool) 0x555555a4c036
11 SkCanvas::onDrawPath(SkPath const&, SkPaint const&) 0x5555558bcf5f
12 SkCanvas::drawPath(SkPath const&, SkPaint const&) 0x5555558ba408
Frame_295.skp

Christopher Dalton

unread,
Jul 5, 2020, 6:34:59 PM7/5/20
to skia-d...@googlegroups.com
Hi Jean-Claude,

Thanks for including the stack trace! It looks like you are hitting a branch that crops your path. The slowness you are seeing is from the CPU generating a new SkPath that is cropped by the canvas bounds.

We have to crop with this particular path renderer because when a path is extremely large (in this case larger than 64k x 64k pixels after transformation: https://github.com/google/skia/blob/master/src/gpu/ccpr/GrCoverageCountingPathRenderer.h#L78) 32-bit floating point can run out of precision while valuating the implicit cubic function.

When you draw at these zoom levels is it possible for you provide a different SkPath to Skia that isn't so large? You can use PathOps if needed to crop your own path to the portion you expect to draw:

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/7f949da9-6ff2-47ca-a638-ebe6e0088744%40www.fastmail.com.

Jean-Claude Monnin

unread,
Jul 6, 2020, 8:16:05 PM7/6/20
to 'Christopher Dalton' via skia-discuss
Hi Christopher,

Thanks for the useful feedback.

I guess there are 3 options to tackle the issue:
  • Use PathOps to crop the path as you suggested before supplying the path . I can't do it once at loading time and I would need to re-crop it occasionally as the view changes. I'm afraid to get periodically very slow frames with it as the cropping seems to the be cause of the issue in the first place.
  • Triangulate the path upfront as outlined in the "SkPath to SkVertices" post. This could be done once at loading time and presumably the rendering would be faster afterwards (this particular path is static and never changes). The drawback is that it relies on non-public interfaces. I haven't tried or benchmarked that yet.
  • Use the same render path as Chrome (I don't know how to achieve that).
    Chrome doesn't have that issue. It seems to send the path as such to skia; without pre-cropping or upfront triangulation (see [1] for how I came to that conclusion). Admittedly I'm completely unfamiliar with the rendering pipeline of chrome. How does chrome work around the issues? Why does the WASM debugger with GPU doesn't trigger the same issue?

I would be grateful for any followup advice as I'm slightly uncomfortable in going the PathOps route for the reason mentioned above (and I'm really curious to understand the difference to chrome).

Kind regards,
Jean-Claude


[1] - Trying to reproduce the same issue in chrome
------------------------------------------------------------------------
I generated a svg with similar view, which rendered quickly. Then I extracted a skp as outlined in (https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/saving-skp-s-from-chromium).
I could see the original path in the captured skp file (eg. it wasn't cropped). WASM debugger was rendering it quickly (both in software or GPU mode). When I open this chrome generated skp file in `skiaserve` from my own build, it's very slow again.
What could trigger the different render path in my own build vs the chrome rendering (SVG and the Skia WASM debugger)?

Christopher Dalton

unread,
Jul 6, 2020, 8:58:00 PM7/6/20
to skia-d...@googlegroups.com
Why would you have to triangulate the path yourself? Why not just disable antialias on the paint or use a render target with MSAA and let Skia triangulate it for you?

Jean-Claude Monnin

unread,
Jul 6, 2020, 9:35:54 PM7/6/20
to 'Christopher Dalton' via skia-discuss
The app used software rendering initially, and I wasn't even aware Skia would use MSAA if available. I use a OpenGL without MSAA. This wasn't a deliberate choice, but just how the conversion to the GPU surface happened at the time.
I've not found anything about it in the documentation (I might have missed it).

Is it correct to assume:
- The recommended mode is to enable MSAA on the OpenGL context, and then the anti-alias option in the paint can be disabled and it will look similar than to software renderer with anti-aliasing enabled?
- Using the MSAA context with anti aliasing on paint disabled, it's likely that the slow path I was hitting before is avoided?

Christopher Dalton

unread,
Jul 7, 2020, 3:11:24 AM7/7/20
to skia-d...@googlegroups.com
Almost.

Leave anti-aliasing enabled on the paint if you want the path to look smooth. If not, Skia will call "glDisable(GL_MULTISAMPLE)". I brought up disabling AA simply because that's a way to make Skia use triangulation on a non-MSAA render target.

If you render to a GrRenderTarget with fSampleCnt > 1, then Skia will use triangulation internally and you shouldn't have to think about it.

And yes, using triangulation will avoid the slow cropping you ran into. But all that being said, the path you are drawing is larger than  64k x 64k pixels. That's a lot of triangles! And 99.9% of it will be offscreen. It might be fine, but it's possible it might be slow too. I'm curious to hear how it works for you.


Reply all
Reply to author
Forward
0 new messages