Open Bug 1868689 Opened 3 months ago Updated 2 months ago

Slow `CanvasRenderingContext2D.drawImage()` with SVGs in a large rect

Categories

(Core :: Graphics: Canvas2D, defect)

Firefox 120
defect

Tracking

()

UNCONFIRMED

People

(Reporter: vania6600, Unassigned)

Details

Attachments

(2 files)

Attached file about:support

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.

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>

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.

Component: Untriaged → Graphics: Canvas2D
Product: Firefox → Core
Attached file cvsv.html

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.

Can confirm disabling gfx.canvas.accelerated and gfx.canvas.accelerated.force-enabled mitigates the issue.

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?

Flags: needinfo?(lsalzman)

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

Flags: needinfo?(lsalzman)

The severity field is not set for this bug.
:lsalzman, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(lsalzman)
Severity: -- → S3
Flags: needinfo?(lsalzman)
You need to log in before you can comment on or make changes to this bug.