Slow `CanvasRenderingContext2D.drawImage()` with SVGs in a large rect
Categories
(Core :: Graphics: Canvas2D, defect)
Tracking
()
People
(Reporter: vania6600, Unassigned)
Details
Attachments
(2 files)
User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0
Steps to reproduce:
Sample page:
<!DOCTYPE html>
<html>
<body style="margin: 0">
<span id="delta" style="position: absolute"></span>
<canvas id="canvas"></canvas>
<script>
function createSolidGradient(r) {
const g = ctx.createRadialGradient(0, 0, 0, 0, 0, r)
g.addColorStop(0, 'rgba(255, 0, 0, 0.5)')
g.addColorStop(0.1, 'rgba(0, 0, 255, 0.5)')
g.addColorStop(0.5, 'rgba(0, 255, 0, 0.5)')
g.addColorStop(1, 'rgba(255, 0, 255, 0.5)')
g.addColorStop(1, 'rgba(0, 0, 0, 0)')
return g
}
function render() {
const start = performance.now()
ctx.clearRect(0, 0, w, h)
ctx.fillStyle = g
ctx.fillRect(0, 0, s, s)
// ctx.drawImage(img, 0, 0, s, s)
const delta = performance.now() - start
document.getElementById('delta').innerText = delta
window.requestAnimationFrame(render)
}
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const w = 1024
const h = 1024
canvas.width = w
canvas.height = h
const img = new Image()
img.src = 'https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/osa.svg'
const s = 1000
const g = createSolidGradient(s)
window.requestAnimationFrame(render)
</script>
</body>
</html>
Actual results:
When s
is set to 5000, frame takes ~1ms to render (fast) profile.
When s
is set to 6000, frame takes ~9ms to render (slow) profile.
Expected results:
Performance should not drop when drawing large SVGs off-screen.
Reporter | ||
Comment 1•1 year ago
|
||
Nicely formatted example page:
<!DOCTYPE html>
<html>
<body style="margin: 0">
<span id="delta" style="position: absolute"></span>
<canvas id="canvas"></canvas>
<script>
function render() {
const start = performance.now()
ctx.clearRect(0, 0, w, h)
ctx.drawImage(img, 0, 0, s, s)
const delta = performance.now() - start
document.getElementById('delta').innerText = delta
window.requestAnimationFrame(render)
}
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const w = 1024
const h = 1024
canvas.width = w
canvas.height = h
const img = new Image()
img.src = 'https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/osa.svg'
const s = 6000
window.requestAnimationFrame(render)
</script>
</body>
</html>
Comment 2•1 year ago
|
||
The Bugbug bot thinks this bug should belong to the 'Core::Graphics: Canvas2D' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Comment 3•1 year ago
|
||
Comment 4•1 year ago
|
||
Everything looks to be happening the same all the way down to the VectorImage::Draw call for the fast/slow cases. I think maybe we are falling off some fast path in the accelerated canvas backend as this stays fast when accelerated canvas is turned off.
Reporter | ||
Comment 5•1 year ago
|
||
Can confirm disabling gfx.canvas.accelerated
and gfx.canvas.accelerated.force-enabled
mitigates the issue.
Comment 6•1 year ago
|
||
And on Windows (where we use d2d not accelerated canvas) it remains fast at 6000 pixels.
Perhaps the increased size means the accelerated canvas backend fails to cache something? It looks like we do the same work for the first draw, but after that 5000 is really quick, 6000 is slow.
5000 pixels, fast
https://share.firefox.dev/488TQnS
6000 pixels, slow
https://share.firefox.dev/4aes4Z0
Lee, do you know is there any place in the accelerated canvas backend where we might fall off a cache if the image size gets too large?
Comment 7•1 year ago
•
|
||
https://searchfox.org/mozilla-central/source/dom/canvas/DrawTargetWebgl.cpp#1668
gfx.canvas.accelerated.max-surface-size defaults to 5280, you could try pushing it higher and see
Comment 8•1 year ago
|
||
The severity field is not set for this bug.
:lsalzman, could you have a look please?
For more information, please visit BugBot documentation.
Updated•1 year ago
|
Description
•