Canvas drawImage() severe performance issue on macOS from v62
Categories
(Core :: Graphics: Canvas2D, defect, P3)
Tracking
()
People
(Reporter: register, Assigned: jgilbert)
References
(Depends on 1 open bug, Regression)
Details
(Keywords: perf, regression)
Attachments
(2 files)
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Steps to reproduce:
I draw an image on a "2d" context of an HTML5 "<canvas>" element repeatedly within an animation framework via the "window.requestAnimationFrame()" function.
I have attached a standalone HTML file which contains some JavaScript to run the little performance measurement.
Actual results:
When drawing the image over a canvas via a "2d" context, the performances are very bad from Firefox v62 on macOS onwards.
On my machine, a MacBook Pro from 2015 equipped with a 2,8 GHz Intel Core i7, here are the results regarding the drawing durations, following the execution of the attached benchmark with the "Duration in milliseconds" set to its default value of 5000, "Use requestAnimationFrame" checked (as by default), "Scaling factor" set to its default value of 1 and "Use the "context.clearRect()" method in addition" unchecked (as by default):
- on Firefox Quantum v61.0b9 (64-bit): 0.115 ms
- on Firefox Quantum v62 (64-bit): 3.326 ms
- on Firefox Developer Edition v72.0b3 (64-bit): 3.312 ms
On Firefox, in order to have a descent time recording precision, the "privacy.reduceTimerPrecision" property has been set to "false" via the "about:config" page.
From my readings, this may be due to the Mercurial change https://hg.mozilla.org/releases/mozilla-beta/rev/3c6db05ccd3d, discussed in bug 1468801 (https://bugzilla.mozilla.org/show_bug.cgi?id=1468801), but I'm not sure.
As a comparison on the same machine, with the same settings, on other browser, I get:
- on Chromium v78.0.3904.97 (64 bits): 0.049 ms
- on Safari Technology Preview Release 93 (Safari 13.1, WebKit 14609.1.5): 0.106 ms, though the result is not reliable because of the lack of precision of the "performance.now()" function.
This shows that the performance gap has a magnitude of more than 40 times compared to the rest of the industry.
Expected results:
The performance should not be decreased by a magnitude of more 20 times, as we experience it when passing from Firefox v61 to v62, given that this performance issue is still the same with the v72 of Firefox.
This is a big performance issue and many canvas-based applications suffer it and are now unusable on Firefox.
Note that this performance issue does not seem to occur on Windows, but is also experienced on Android.
If I can help, please tell me, because I really need this performance issue to be fixed, as this makes the animation technology that my company has developed unusable on Firefox macOS (and Android), while it is satisfactory on all other browsers.
Reporter | ||
Updated•5 years ago
|
Reporter | ||
Updated•5 years ago
|
Reporter | ||
Updated•5 years ago
|
Assignee | ||
Comment 1•5 years ago
|
||
Thanks for the report!
While this microbenchmark definitely surfaces that this operation is slower in Firefox, I'd like to know more about your actual usecase to see what we can do there.
Assignee | ||
Comment 2•5 years ago
|
||
I think I can effectively reproduce this on Windows with d2d disabled. (disable via pref and restart the browser)
One thing that helps a ton is context.imageSmoothingEnabled = false;
, if "nearest" filtering is acceptable, as "linear" filtering is slow on the CPU.
Caching the pre-resized image as an ImageData or CanvasPattern yields similar numbers, so it sounds like we do hit the fastpath for 1:1 rendering skipping filtering. The pre-resized-putImageData path in particular seems to be fastest, which does match my expectations.
It's worth noting that while I do expect Chrome's hardware acceleration here to be faster, it also hides the true time it takes (particularly on Android), making this hard to compare apples-to-apples.
It would be great to learn more about the actual usecase in order to move this forward.
Reporter | ||
Comment 4•5 years ago
|
||
Jeff, thank you for taking the time to review this issue.
Here is some feedback.
-
Regarding the optimisation with
CanvasRenderingContext2D.imageSmoothingEnabled = false
, I have already tried out — you can see that this line is commented-out in the HTML that I provided — and I did not notice any performance increase (the image mapping interpolation is not bilinear but linear in that case, from what I understand, which may help a lot). I re-ran the test with this statement and did not notice any performance improvement. -
I understand that it's not expected that the
CanvasRenderingContext2D.putImageData()
function be faster.
As you mention, a micro benchmark is alway a bit suspicious, and to handle with great care. I think though, that mine is simple enough to stress the performance fall from Firefox 62.
Our use case is that we have authored an animation engine framework library based on the canvas, which draws at a 60 Hz frame rate. This engine works with shapes, texts and images (we name particles), organised in layers, for which key frame states are defined as well as interpolators. This engine uses the HTML5 canvas to render, resorting to the "2d" context. As far as images are concerned, they can be moved, rotated, scaled down dynamically. This is where we require much performance in terms of printing an image over the canvas. Note that, In the example that I provided, we indeed print the image on a 1:1 basis, but in our engine, this is rarely the case.
In order to move forward, do you want me to share some animations generated with our library (and in that case, I prefer to share this privately, if possible) ? What else can I provide and prepare, in order to ease the resolution?
Reporter | ||
Comment 5•5 years ago
|
||
Hello Miko.
I noticed that you turned the priority of this issue to P3, which, from my understanding, may delay a lot its resolution.
I insist on the fact that this issue causes on macOS and Android a performance penalty of a factor 10 compared to a v62 of Firefox, hence this is a major regression which impacts all applications and libraries relying on the HTML5 canvas. In my issue post, I did not mention that most of the CanvasRenderingContext2D
primitives are impacted, like the clearRect()
, fillRect()
methods, for instance, hence, this performance issue is overall to the canvas.
What's more, the issue does not seem to occur on iOS and Windows, which is not consistent.
I suggest that the priority be increased, because, in the current state, this makes Firefox unable to support some canvas based applications and libraries for end-users on those two platforms, which does not play on Firefox's side.
What can I do, please, in order to have this issue more prioritized? I'm available for a live discussion if this can help explain further and motivate my request, which will benefit many others.
Updated•5 years ago
|
Updated•5 years ago
|
Updated•5 years ago
|
Comment 6•5 years ago
|
||
Jeff, Lee - does this look like a situation where WebGL would help?
Comment 7•5 years ago
|
||
I profiled this and two other testcases supplied by Édouard on macOS, and it seems that the majority (80-90%) of the time is spent inside Skia code.
Comment 8•5 years ago
|
||
(In reply to Jessie [:jbonisteel] plz needinfo from comment #6)
Jeff, Lee - does this look like a situation where WebGL would help?
Yes, this is exactly a use case where WebGL is the desired method of acceleration. Targeting 60 Hz drawing a bunch of geometry with filtering.
It is going to be a while before we can investigate non-SkiaGL means of acceleration for canvas, so using WebGL potentially with some form of Js canvas emulation library is the recommended resolution in the meanwhile.
Assignee | ||
Updated•5 years ago
|
Updated•5 years ago
|
Comment hidden (advocacy) |
Comment hidden (advocacy) |
Assignee | ||
Comment 12•5 years ago
|
||
Sorry all, this fell out of my active list. I am still working on this.
Comment hidden (advocacy) |
Comment 14•5 years ago
|
||
Is this the reason why games like diep.io and florr.io don't run at 60fps on Firefox on MacOS ?
Comment hidden (advocacy) |
Reporter | ||
Updated•5 years ago
|
Comment 16•5 years ago
|
||
Patrick, do you know what the status of your work with regards to pathfinder acceleration and Canvas2D is?
Comment 17•5 years ago
|
||
(In reply to Lee Salzman [:lsalzman] from comment #16)
Patrick, do you know what the status of your work with regards to pathfinder acceleration and Canvas2D is?
Most canvas features are implemented, and I'd say it's ready for testing if someone wants to get started on the integration work.
Comment 18•5 years ago
|
||
(In reply to Patrick Walton (:pcwalton) from comment #17)
(In reply to Lee Salzman [:lsalzman] from comment #16)
Patrick, do you know what the status of your work with regards to pathfinder acceleration and Canvas2D is?
Most canvas features are implemented, and I'd say it's ready for testing if someone wants to get started on the integration work.
Jessie, do we have someone with some free time on their hands who might want to investigate integrating pathfinder into Canvas2D with Patrick?
Comment 19•5 years ago
|
||
Time to integrate Pathfinder is something we can investigate more closely in H2, but is more of a longer term project.
jgilbert - if you can provide more context about your potential workaround idea, that would be great.
Comment hidden (advocacy) |
Comment 21•4 years ago
|
||
We do plan on fixing this, it just won't be soon. Unfortunately the previous solution that we had wasn't very maintainable and so we decided to remove it.
It would be helpful if you could share some urls that show this problem so we get a better sense of the impact on users. i.e. do you have examples of sites that were usable before and aren't after?
Comment 22•4 years ago
|
||
Just adding a needinfo here so we could get some examples of sites where this is a problem as mentioned in comment 21.
Reporter | ||
Comment 23•4 years ago
|
||
Here is an example which demonstrates the performance issue (working on mobile and desktop): https://app.motion.ly/#/share/a29wcGFzb2Z0LmFzc2V0cy5yZWRpc3BsYXkuaW8vU2hhcmUvNTE4MTk5MTMxMzk5NzgyNC5odG1s.
This page is a basic HTML page which hosts an interactive animation, which plays like an Instagram story (press on the left or the right to revert to the previous or skip to the next chapter). The rendering engine uses the HTML <canvas>. If you focus on the "CanvasRenderingContext2D.drawImage()" function (as stated when the issue was reported) and you compare the performance before the Firefox v62 to the current version of the browser, you will notice the 10 times factor decrease. As a comparison, open it in Chromium or Safari, and you will notice the big performance difference.
Comment 24•4 years ago
|
||
Thanks for the example. I took a profile here: https://share.firefox.dev/2O0BrlR. While not great, and definitely bottlenecked on canvas drawImage the site ran fine for me and was 84% idle.
I'm running on a pretty powerful machine. Are you seeing a lot worse elsewhere?
Reporter | ||
Comment 25•4 years ago
|
||
Thank you for having taken the time to profile the page. I agree, the bottleneck is definitively on the CanvasRenderingContext2D.drawImage()
method.
I realize that the width of the animation sample that I've shared was not enough to pinpoint and emphasize the performance issue, hence I've modified it so that it now takes 30% of the viewport width (instead of 20%, earlier). If you capture a profile again while the story transitions from one chapter to the following one, you will notice the performance issue (and if you also take a look at your computer CPU / GPU, you will see that it dramatically increases). At least, this is what I experience on a MacBook Pro mid-2015, running macOS 10.14.6, equipped with a 2,8 GHz Intel Core i7 CPU, 16 Go 1600 MHz DDR3 of RAM and an Intel Iris Pro 1536 Mo GPU (which remains a steady machine, on which the Monitor states that about 80% of the CPU is taken by the " Firefox Developer EditionCP Web Content" process during the animation).
I have attached my profile so that you may compare it with yours. If you run the same page on a Firefox v61, you will notice the discrepancy in terms of profile and CPU.
Reporter | ||
Comment 26•4 years ago
|
||
A profile taken on Firefox Developer Edition v79.0b4 when running the page https://app.motion.ly/#/share/a29wcGFzb2Z0LmFzc2V0cy5yZWRpc3BsYXkuaW8vU2hhcmUvNTE4MTk5MTMxMzk5NzgyNC5odG1s.
Comment 27•4 years ago
|
||
BTW, is it OK that the status still listed as UNCONFIRMED?
Assignee | ||
Comment 28•4 years ago
|
||
Good catch, we definitely see this.
Updated•4 years ago
|
Updated•4 years ago
|
Comment 29•4 years ago
|
||
This is affecting my HTML5 game where sprites are drawn repeatedly with drawImage(). Unfortunately, the game is nearly unplayed on FF whereas it runs at 60fps on Chrome and Safari. I am running this on a Mac with the exact same stats as Édouard Mercier, down to the OSX version:
MacBook Pro mid-2015, running macOS 10.14.6, equipped with a 2,8 GHz Intel Core i7 CPU, 16 Go 1600 MHz DDR3 of RAM and an Intel Iris Pro 1536 Mo GPU
Comment 30•4 years ago
|
||
I wrote an in-depth post on my drawImage() use case here, in case it is helpful for context: https://www.notion.so/markracette/Pt-3-Using-Bitmap-Caching-to-Unlock-60fps-in-3-Dimensions-c4054f1477dd4f628ddcc7fc2821c754#6f4be5b6a9f842acbe3d28fbec388023
Also noting that I was able to write a drawImage() implementation in WebGL (more info in post), but it has some major pitfalls, namely not being able to mix 2D and 3D content.
Comment 31•4 years ago
|
||
Hi we are facing performance issue in latest version Firefox , when we tested in older versions which are less than 62 we didn’t find any performance issue. And not able to figure any major difference in performance monitoring as well except drawing is taking much time in current version compared to older versions , any updates or changes that could be drawn with canvas2d renderer to improve performance in current Firefox version(83)..thanks
Comment hidden (advocacy) |
Updated•4 years ago
|
Comment 33•4 years ago
|
||
And not able to figure any major difference in performance monitoring as well except drawing is taking much time in current version compared to
older versions
Is there any public site we could get a performance profile off of? From my understanding it's interesting to see exactly where the bottlenecks are.
Reporter | ||
Comment 34•4 years ago
|
||
Thank you for considering this issue.
You make a take a look at this demo, https://share.motion.ly/a29wcGFzb2Z0LmFzc2V0cy5yZWRpc3BsYXkuaW8vU2hhcmUvNTE4MTk5MTMxMzk5NzgyNC5odG1s, which is public and demonstrates the performance issue.
This page is a basic HTML page which hosts an interactive animation, which plays like an Instagram story (press on the left or the right to revert to the previous or skip to the next chapter). The rendering engine uses the HTML <canvas>. If you focus on the "CanvasRenderingContext2D.drawImage()" function (as stated when the issue was reported) and you compare the performance before the Firefox v62 to the current version of the browser, you will notice the 10 times factor decrease. As a comparison, open it in Chromium or Safari, and you will notice the big performance difference.
If you need more samples to isolate and highlight the issue, please let me know.
Comment 35•4 years ago
|
||
Thank you! Canvas performance is on the radar of the graphics team and we expect improvements there next half, though I of course can't guarantee they will fix this particular case. But it gives us insight which issues people hit in the field.
AFAIK one known performance difference here is that we use software rendering on macOS, and Chromium/Safari use HW acceleration there. The latter isn't necessarily always faster (we used to do this and changed it back!), and it might be irrelevant to this problem, but differences in behavior aren't unexpected. We probably don't want to be 10x as slow though.
Edit: feedback from gfx is that this indeed something they expect HW acceleration would improve
Comment 36•3 years ago
|
||
Can we please get some update on that?
Potentially, could this issue be escalated to P2? I guess it's not right to have orders of magnitude worse performance on macOS compared to Windows for the same product for years (!), while there's clearly a solution every other browser uses.
Comment 37•3 years ago
|
||
https://github.com/jagenjo/Canvas2DtoWebGL can improve drawImage by translating Canvas2D to WebGL.
Select "Benchmark: drawImage" and then click on Canvas2D or WebGL: https://tamats.com/projects/canvas2DtoWebGL/demo/
Comment 38•3 years ago
|
||
(In reply to metaxaos from comment #36)
Can we please get some update on that?
Potentially, could this issue be escalated to P2? I guess it's not right to have orders of magnitude worse performance on macOS compared to Windows for the same product for years (!), while there's clearly a solution every other browser uses.
We're currently prototyping a solution to this and hope to have something you can try in Nightly by the end of the year.
Comment hidden (advocacy) |
Comment 40•3 years ago
|
||
Hi all,
We're also experiencing this problem of getImageData / drawImage performance. Here is a demo to reproduce
https://demo.scichart.com/javascript-multi-pane-stock-charts
Try using the mouse wheel in this chart demo on Firefox vs. Chrome. The performance difference is HUGE!
What we're doing. We have one WebGL canvas which we draw to, and we use getImageData() / drawImage() to read back pixels from webgl and write into HTML5 canvas. This gets around the limitation of number of webgl canvases per browser.
The only workaround we have is to render directly to WebGL canvas but that limits the # of charts we can have on a screen.
Performance difference is massive between Firefox & Chrome. So much so we're recommending to our users they must use chrome.
Any help appreciated. Can also supply further info if requested.
Comment 41•3 years ago
|
||
getImageData() should never be used where high performance is expected due to the cost of reading back pixels from an accelerated context. This, in principle, defeats most attempts at acceleration because you are forcing the GPU and CPU to synchronize to read back the pixel data and then trying to re-upload it to a GPU context again forces the synchronization back in the other direction.
Comment 42•3 years ago
|
||
(In reply to Lee Salzman [:lsalzman] from comment #41)
getImageData() should never be used where high performance is expected due to the cost of reading back pixels from an accelerated context. This, in principle, defeats most attempts at acceleration because you are forcing the GPU and CPU to synchronize to read back the pixel data and then trying to re-upload it to a GPU context again forces the synchronization back in the other direction.
True, but it performs perfectly well on Google chrome just nor Firefox
Do you have another suggestion for WebGL canvas sharing (e.g. one master WebGL canvas, multiple target canvases on page)? The only one I can think of is a single shared WebGL context and getImageData() / createImage
Updated•3 years ago
|
Assignee | ||
Updated•3 years ago
|
Assignee | ||
Comment 43•3 years ago
|
||
This sounds different, so I've filed bug 1748592 for you.
This bug is more about repeated drawImage with the same content being slow, and it sounds like you're asking for something different.
Assignee | ||
Comment 44•3 years ago
|
||
(In reply to Jeff Muizelaar [:jrmuizel] from comment #38)
(In reply to metaxaos from comment #36)
Can we please get some update on that?
Potentially, could this issue be escalated to P2? I guess it's not right to have orders of magnitude worse performance on macOS compared to Windows for the same product for years (!), while there's clearly a solution every other browser uses.We're currently prototyping a solution to this and hope to have something you can try in Nightly by the end of the year.
For people wanting to follow along, the initial prototype for this landed in bug 1739448, and continues to look promising.
Comment 45•2 years ago
|
||
Redirect a needinfo that is pending on an inactive user to the triage owner.
:lsalzman, since the bug doesn't have a severity set, could you please set the severity or close the bug?
For more information, please visit auto_nag documentation.
Comment 46•2 years ago
|
||
What issues can be resolved by acceleration are being resolved by accelerated canvas in bug 1741501. Otherwise, just going to resolve this thread as inactive for now because its drifting too much and there is no clear resolution. It will either be resolved by the landing of accelerated canvas, or if it doesn't, a follow-up can be dealt with at that time.
Comment hidden (advocacy) |
Comment 48•2 years ago
|
||
(In reply to Édouard Mercier from comment #47)
You must be kidding, I guess. A regression with a 10x factor reported 3 years on a major component of the web, a ticket with explanation, reproducible steps, someone ready to support and provide help. And Mozilla ends up classifying the file: it says a lot to the governance of this Foundation and of its future. Good luck!
As I noted in comment 46, bug 1741501 is a multi-year long project that is still ongoing to address Canvas2D performance. Please don't think we're ignoring the issue. Work has been ongoing all this time. You can play with accelerated canvas even now by just toggling the "gfx.canvas.accelerated" pref if you feel the need to check in on the work that is already there (it is turned on by default in nightly). We're taking the time to make sure everything is awesome before we roll it out to release, though.
Criticism is, of course, within everyone's rights, but constructive criticism and development feedback is far more useful to us with regards to Canvas2D acceleration development. We have a number of volunteers who have been offering us constructive feedback and testing throughout the development process and they have been invaluable. If you choose to go that way instead, you're certainly welcome.
Description
•