Very slow performance when zooming and scrolling PDF in Fenix
Categories
(GeckoView :: PDF Viewer, defect)
Tracking
(Performance Impact:medium)
Performance Impact | medium |
People
(Reporter: denispal, Unassigned)
References
(Blocks 2 open bugs)
Details
Attach (recommended) or Link to PDF file here:
Steps to reproduce the problem:
- Load https://turtlejacks.com/wp-content/uploads/2021/05/TJS-11514-Nutritional-Menu-Guide-Update-2024.pdf in Fenix
- Zoom in and scroll around. The content takes a very long time to update and refresh.
Profile: https://share.firefox.dev/3OMqTGC
Reporter | ||
Updated•2 months ago
|
Reporter | ||
Updated•2 months ago
|
Reporter | ||
Comment 1•2 months ago
|
||
I can reproduce this using other PDF's as well after zooming in. Here is another example PDF https://assets.metrolinx.com/image/upload/v1729508831/Documents/GO/full-schedules/FS03112024/TABLE01.pdf Performance is very bad after zooming in enough.
Reporter | ||
Comment 2•2 months ago
|
||
Another profile using the gecko profiler this time: https://share.firefox.dev/3VAOcqu
Comment 3•2 months ago
|
||
A lot of CPU-side copies and texture upload. Lee, can you take a look?
Comment 4•2 months ago
•
|
||
Part of the problem seems to be the sheer amount of repaints being triggered. This causes a lot of shared memory traffic to shuttle things to the compositor every time, and I don't think we ever found a great way to make this better yet.
Marco/Calixte, do you know why pdf.js is triggering so many repaints in the middle of drawing this PDF?
Updated•2 months ago
|
Comment 5•2 months ago
|
||
How is the performance on Chrome?
Reporter | ||
Comment 6•2 months ago
|
||
Chrome just opens the default PDF viewer app. Actually even after downloading the file in Firefox, after I click open Firefox just ends up opening it again inside the browser which is also a problem.
Reporter | ||
Comment 7•2 months ago
|
||
We discussed this bug in our android performance meeting. Considering the performance impact here is quite severe and will likely affect anyone reading a PDF (via reading a menu at a restaurant, or train schedule, etc) we thought it's best to bump this up to S2.
Reporter | ||
Comment 8•2 months ago
|
||
The performance is significantly better when opening the PDF through https://mozilla.github.io/pdf.js/web/viewer.html link directly instead of opening the PDF through the browser. I took a profile of each situation:
Open PDF in App: https://share.firefox.dev/3P1myzp
Open PDF through link: https://share.firefox.dev/3ZJEweu
Jeff helped look at the profiles and indicated that we might not be using the GPU canvas when opening the PDF in the app.
Comment 9•2 months ago
|
||
From my perspective, the pdf seems to be normal.
While zooming, the canvas is scaled in using CSS and once zooming is done, after a small delay, the canvas is redrawn.
The viewer in Fenix is disabling hardware acceleration (i.e. we pass willReadFrequently: true
when getting the canvas context) when the viewer in the link isn't.
We decided to disable hardware acceleration in bug 1902012 because of wrong rendering or poor performances issues.
Right now it's disabled on every platform, :jrmuizel, do you think we should enable it for Fenix only ? or could we meet the same kind of issues we already saw on mac (perf issues with filters) or on linux (bad rendering) ?
Comment 10•1 month ago
|
||
I think we need to better understand the performance problem that's happening in software mode before we consider changing to gpu acceleration.
Performance is going to be a lot more unpredictable with gpu acceleration so my preference is to make sure we're doing things right with gpu acceleration disabled before we consider turning it back on.
Comment 11•26 days ago
|
||
30% of the main thread time appears to be in this stack:
_memcpy_aarch64_simd [libc.so]
SkBitmap::writePixels(SkPixmap const&, int, int) [gfx/skia/skia/src/core/SkBitmap.cpp]
SkBitmapDevice::onWritePixels(SkPixmap const&, int, int) [gfx/skia/skia/src/core/SkBitmapDevice.cpp]
SkDevice::writePixels(SkPixmap const&, int, int) [gfx/skia/skia/src/core/SkDevice.h]
SkCanvas::writePixels(SkImageInfo const&, void const*, unsigned long, int, int) [gfx/skia/skia/src/core/SkCanvas.cpp]
mozilla::gfx::DrawTargetSkia::CopySurface(mozilla::gfx::SourceSurface*, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::gfx::IntPointTyped<mozilla::gfx::UnknownUnits> const&) [gfx/2d/DrawTargetSkia.cpp]
mozilla::layers::TextureClient::CopyToTextureClient(mozilla::layers::TextureClient*, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*, mozilla::gfx::IntPointTyped<mozilla::gfx::UnknownUnits> const*) [gfx/layers/client/TextureClient.cpp]
mozilla::layers::PersistentBufferProviderShared::BorrowDrawTarget(mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&) [gfx/layers/PersistentBufferProvider.cpp]
mozilla::dom::CanvasRenderingContext2D::BorrowTarget(mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, bool) [dom/canvas/CanvasRenderingContext2D.cpp]
mozilla::dom::CanvasRenderingContext2D::EnsureTarget(mozilla::ErrorResult&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const*, bool, bool) [dom/canvas/CanvasRenderingContext2D.cpp]
mozilla::dom::CanvasRenderingContext2D::EnsureTarget(mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const*, bool, bool) [dom/canvas/CanvasRenderingContext2D.h]
mozilla::dom::CanvasRenderingContext2D::Save() [dom/canvas/CanvasRenderingContext2D.cpp]
mozilla::dom::CanvasRenderingContext2D_Binding::save(JSContext*, JS::Handle<JSObject*>, void*, JSJitMethodCallArgs const&) [dom/bindings/CanvasRenderingContext2DBinding.cpp]
Perhaps we can avoid copying the previous buffer's contents somehow. Calixte, do you know where this canvas.save()
call is coming from in pdf.js?
Comment 12•26 days ago
|
||
According to the profile, the ctx.save
are called from showText
:
https://github.com/mozilla/pdf.js/blob/877f69886c3e000fb7be2d82d536476032f2b8e4/src/display/canvas.js#L2168
(there are few other save
in this function but there aren't used for this pdf).
It's called 1801 times.
So as said before, this pdf has nothing special except the page dimension (11 x 31.5 in).
I don't see any perf problems on desktop, so it seems to be specific to Android, or am I missing something ?
That said, in reading the docs here:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
I'm not sure to understand (I'm not a gfx expert though...) why we need to do some pixel stuff when we just want to save some basic properties.
Comment 13•15 days ago
|
||
(In reply to Denis Palmeiro [:denispal] from comment #8)
The performance is significantly better when opening the PDF through https://mozilla.github.io/pdf.js/web/viewer.html link directly instead of opening the PDF through the browser. I took a profile of each situation:
Open PDF in App: https://share.firefox.dev/3P1myzp
Open PDF through link: https://share.firefox.dev/3ZJEweuJeff helped look at the profiles and indicated that we might not be using the GPU canvas when opening the PDF in the app.
Do you still see differences between opening the PDF directly through the browser and opening it in https://mozilla.github.io/pdf.js/web/viewer.html?
What does the performance look like in Chrome when opening the PDF in https://mozilla.github.io/pdf.js/web/viewer.html?
Comment 14•15 days ago
•
|
||
If you look at https://share.firefox.dev/3VAOcqu it looks like pdf.js is painting every requestAnimationFrame. This causes us to do an upload of what might be a large canvas every requestAnimationFrame. The solution here is likely that pdf.js needs to break the pdf into tiles of one canvas each and then paint them less aggressively.
Updated•15 days ago
|
Comment 15•15 days ago
|
||
Ah yes, during zooming you just want the zooming itself to be responsive, you don't want it to be rendered "sharp" at every zoom level.
I agree, when the zoom level changes during pinch zooming, the existing canvas should be scaled. The actual repainting into that canvas should happen at a much lower rate.
Comment 16•15 days ago
|
||
And tiling the canvas would remove the cost from uploading texture bytes for the parts of the canvas that are outside the screen.
Comment 17•14 days ago
|
||
Scaling the existing content during zooming should also fix the main thread performance, where the bulk of the time is spent allocating and copy data into new backbuffers due to the current frontbuffer still be read locked. Not having to make a new backbuffer every frame during zooming would be massive.
We have a similar thing in webrender called "low quality pinch zoom". We scale the existing content whilst a pinch zoom is active, then render again at the new scale when the zoom ends. Additionally we render at the new scale during an active pinch zoom if the zoom level doubles or halves -- when zooming in this prevents the content getting too blurry. Importantly, when zooming out this prevents having a huge number of small tiles on screen at once, which caused serious performance issues. Something to look out for.
As a secondary thought, in the layers days BufferTextureHost used to be able to drop its read lock once it had uploaded to a GL texture. I don't believe we do that for webrender. If we still see a lot of backbuffer allocations occuring after implementing tiling and scaling-zoom, we could perhaps look in to that too.
Updated•11 days ago
|
Comment 18•11 days ago
|
||
Thanks for the suggestions, we'll see if we can implement the slow refresh first. Tiling (https://github.com/mozilla/pdf.js/issues/6419) will require quite some work though, so we need to weigh it against other priorities.
Updated•11 days ago
|
Reporter | ||
Comment 19•8 days ago
|
||
(In reply to Marco Castelluccio [:marco] from comment #13)
Do you still see differences between opening the PDF directly through the browser and opening it in https://mozilla.github.io/pdf.js/web/viewer.html?
What does the performance look like in Chrome when opening the PDF in https://mozilla.github.io/pdf.js/web/viewer.html?
This feels better now than when I first opened this bug, but still a lot of jank and stuttering when scrolling quickly. Performance seems similar between the viewer and in-app however. Chrome does feel smoother when opening the PDF in the viewer, however.
Description
•