Closed Bug 1250073 Opened 8 years ago Closed 8 years ago

Firefox 44.0.2 has performance issues with 'drawImage' for canvas

Categories

(Core :: Graphics: Canvas2D, defect)

44 Branch
All
macOS
defect
Not set
normal

Tracking

()

RESOLVED WONTFIX

People

(Reporter: funda.pulic, Assigned: mchang)

References

()

Details

(Keywords: perf, Whiteboard: [gfx-noted])

Attachments

(7 files, 3 obsolete files)

Attached file index.html (obsolete) —
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36

Steps to reproduce:

The demo creates a grid of tiles with canvas. The tiles are positioned and scaled depending on the amount of tiles we want to add. Variable 'amountOfTiles' can be set to any integer, unfortunately the Firefox 44.0.2 has huge performance issues when set to 200 tiles or even stops executing the JS (>400 tiles). The issue seems to be the 'drawImage' function, executed for each tile.
The weird thing is that Firefox 38.0.1 has no issues with it, even not with 900 tiles or more!

Thanks in advance!

https://jsfiddle.net/funda/t8kromod/


Actual results:

JS stops being executed in FF44.0.2. In FF38.0.1 no issues!!!!


Expected results:

FF 44.0.2 should work fine just like FF 38.0.1
Severity: normal → critical
OS: Unspecified → All
Hardware: Unspecified → All
Attached file app.js (obsolete) —
OS: All → Mac OS X
Attached file index.html (obsolete) —
Attachment #8721919 - Attachment is obsolete: true
Attached image img_grid.jpeg
Attached file app.js
Attachment #8721921 - Attachment is obsolete: true
Attached file index.html
Attachment #8721959 - Attachment is obsolete: true
WFM with FF44 with 500 tiles
I am doing my best
On my MacBook FF44.0.2 stops executing JS.
Model: MacBook Pro (Retina, 13", 2013)
OS: OS X Yosemite 10.10.5
CPU: 2,8 GHz intel Core i7
RAM: 16GB 1600 MHz DDR3
GPU: Intel Iris 1536 MB
Serial-No. C022M829TFH04

On our iMac it works fine.
Model: iMac 27" 2010
OS: OS X Yosemite 10.10.5
CPU: 2,93 GHz intel Core i7
RAM: 12GB 1333 MHz DDR3
GPU: ATI Radeon HD 5750 1024MB
Serial-No. CK0461EYDNR

I've checked the Versions of FF 44.0.2 on both systems with about:config. I've got the same results.

On Windows 7 with FF 44.0.2 it works, too.

Thanks in advance!
Component: Untriaged → Canvas: 2D
Product: Firefox → Core
Also not working for FF on tablet Nexus 9, Android 6.0.1
Whiteboard: [gfx-noted]
If you go to about:config and set the preference "gfx.canvas.azure.accelerated" to false, restart firefox, and load your test again, is it fast again?

900 tiles actually makes my retina macbook pro totally unresponsive, I can't even do force shutdowns, and I have to forcefully shut down my mac.
Flags: needinfo?(funda.pulic)
Keywords: perf
Indeed, that setting fixes it! But how do I ensure that each user visiting out website has this flag set to false?
Flags: needinfo?(funda.pulic)
Indeed, that setting fixed it! But how do I ensure that each user visiting our website has this flag set to false???
Some profiles of this test with 100 tiles. On a retina macbook pro, we're spending large amounts of time in the GPU. Call stack like:

Running Time	Self (ms)		Symbol Name
PresShell::Paint(nsView*, nsRegion const&, unsigned int)
nsLayoutUtils::PaintFrame(nsRenderingContext*, nsIFrame*, nsRegion const&, unsigned int, unsigned int)
nsDisplayList::PaintRoot(nsDisplayListBuilder*, nsRenderingContext*, unsigned int)
mozilla::layers::ClientLayerManager::EndTransaction(void (*)(mozilla::layers::PaintedLayer*, gfxContext*, mozilla::gfx::IntRegionTyped<mozilla::gfx::UnknownUnits> const&, mozilla::gfx::IntRegionTyped<mozilla::gfx::UnknownUnits> const&, mozilla::layers::DrawRegionClip, mozilla::gfx::IntRegionTyped<mozilla::gfx::UnknownUnits> const&, void*), void*, mozilla::layers::LayerManager::EndTransactionFlags)
mozilla::layers::ClientLayerManager::EndTransactionInternal(void (*)(mozilla::layers::PaintedLayer*, gfxContext*, mozilla::gfx::IntRegionTyped<mozilla::gfx::UnknownUnits> const&, mozilla::gfx::IntRegionTyped<mozilla::gfx::UnknownUnits> const&, mozilla::layers::DrawRegionClip, mozilla::gfx::IntRegionTyped<mozilla::gfx::UnknownUnits> const&, void*), void*, mozilla::layers::LayerManager::EndTransactionFlags)
mozilla::layers::ClientContainerLayer::RenderLayer()
mozilla::layers::ClientContainerLayer::RenderLayer()
mozilla::layers::ClientCanvasLayer::RenderLayer()
mozilla::layers::CanvasClientSharedSurface::Update(mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>, mozilla::layers::ClientCanvasLayer*)
mozilla::layers::CanvasClientSharedSurface::UpdateRenderer(mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits>, mozilla::MaybeOneOf<mozilla::layers::ClientCanvasLayer*, mozilla::layers::AsyncCanvasRenderer*>&)
mozilla::gl::SharedSurface_IOSurface::ProducerReleaseImpl()
intelSubmitCommands
IntelCommandBuffer::getNew(GLDContextRec*)
gpusSubmitDataBuffers
IOAccelContextSubmitDataBuffersExt
IOConnectCallStructMethod
IOConnectCallMethod
io_connect_method
mach_msg
(In reply to Funda from comment #12)
> Indeed, that setting fixed it! But how do I ensure that each user visiting
> our website has this flag set to false???

Not really, but it means we're onto a lead about why this is happening! Also just to make sure that I'm reproducing the same problem as you. We have to fix this in Firefox.
Assignee: nobody → mchang
Got exactly the same Problem with my Android phone. When set flag to false, FF mobile does not crash either.
I started looking at this, and essentially it looks like we clone a surface[1] and force a flush of the command buffer [3] once we release the lock [2]. This can take up to 600+ ms on my retina macbook pro, with both the nvidia and intel gpus.

Morris, Jeff - I'm not too familiar with the texture sharing stuff, do you know why we have to clone the surface? A full callstack is in comment 13.

[1] https://dxr.mozilla.org/mozilla-central/source/gfx/layers/client/CanvasClient.cpp?from=CanvasClient.cpp#384
[2] https://dxr.mozilla.org/mozilla-central/source/gfx/layers/client/CanvasClient.cpp?from=CanvasClient.cpp#345
[3] https://dxr.mozilla.org/mozilla-central/source/gfx/gl/SharedSurfaceIO.cpp?from=SharedSurfaceIO.cpp#36
Flags: needinfo?(mtseng)
Flags: needinfo?(jgilbert)
JS should be  executed in FF44.0.2 there is some performance issues.
Hi there,

do you have any new information for us? It is still a big issue for us and we would really appreciate a fix.

Regards,
Funda
Flags: needinfo?(mtseng)
Flags: needinfo?(jgilbert)
Attached file Offline testcase
Zipped testcase for use offline
Not really sure why the flush is taking so long here, but OS X basically says the CPU is waiting for the GPU to finish something. It doesn't seem like creating a new texture, copying the contents to the new shared texture, should take this long.
(In reply to Mason Chang [:mchang] from comment #20)
> Created attachment 8742578 [details]
> 10ms gl flush draw commands
> 
> Not really sure why the flush is taking so long here, but OS X basically
> says the CPU is waiting for the GPU to finish something. It doesn't seem
> like creating a new texture, copying the contents to the new shared texture,
> should take this long.

That flush is similar to glFinish in nature, so it's at least waiting for the GPU to finish rendering.
Depending on the flags associated with the IOSurf, it may be waiting on something else as well.
10ms seems high for this workload, I agree, particularly if it's 10ms every time we call the same workload.

You might test with CGL multithreading disabled.




(In reply to Mason Chang [:mchang] from comment #16)
> I started looking at this, and essentially it looks like we clone a
> surface[1] and force a flush of the command buffer [3] once we release the
> lock [2]. This can take up to 600+ ms on my retina macbook pro, with both
> the nvidia and intel gpus.
> 
> Morris, Jeff - I'm not too familiar with the texture sharing stuff, do you
> know why we have to clone the surface? A full callstack is in comment 13.

We need a copy because content must be preserved between frames, and we haven't written any code to make this copy-on-write.
Severity: critical → normal
The root cause of this problem was that for every tile we created, it would create a new DOM image element. Then, when we went to drawImage(), we'd use this DOM image element and check to see if it was in our Canvas source surface cache. Since each call to drawImage would be a different HTML element, our cache would fail, and we'd have to upload the 2100x2970 image to the GPU, causing the slowdown. This didn't happen before Skia since Quartz doesn't upload the texture to the GPU.

Can you see the attached test case and verifies that this works for you? Basically, I do one new Image() with the source, then once it loads, load up the tiles to refer to the same ImageElement. I can do 500 tiles easily. Thanks!
Flags: needinfo?(funda.pulic)
I'm also going to test out an idea that Seth came up with where we'd cache the source surface based on the image itself and not just the HTML image element.
Hi Mason,

thanks for your reply, I've tried with 900 tiles and it worked for me. We're thinking about a hotfix for our project. But we are still interested in that issue. So keep us please updated. :)

https://jsfiddle.net/t8kromod/5/

Regards,
Funda
Cool, I'll mark this as WONTFIX then.
Bug 1267260 is where mchang is looking at the surface cache.
Status: UNCONFIRMED → RESOLVED
Closed: 8 years ago
Flags: needinfo?(funda.pulic)
Resolution: --- → WONTFIX
See Also: → 1267260
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: