Context Loss with SwiftShader: drawImage Performance and gl.finish() Blocking Behavior

7 views
Skip to first unread message

Matthew Santoro

unread,
Feb 17, 2026, 3:01:09 PM (8 days ago) Feb 17
to WebGL Dev List

Context:

We currently use the following pipeline to draw:

  1. Render to an offscreen framebuffer with MSAA (using gl.createFramebuffer() + gl.renderbufferStorageMultisample())
  2. Blit to resolve MSAA samples (gl.blitFramebuffer())
  3. Call gl.finish() to ensure rendering is complete
  4. Transfer to Canvas2D via CanvasRenderingContext2D.drawImage(webglCanvas, ...)

Problem:

When rendering large/complex scenes using SwiftShader, we're experiencing frequent context losses. We've traced this to Chrome's GPU watchdog timer being exceeded during the drawImage()call. Disabling the watchdog (via --disable-gpu-watchdog) allows us to eventually (after a significant delay) render the scene.

Questions:

  1. Does gl.finish() properly block until rasterization is complete in SwiftShader?

    • The WebGL spec states finish() should "block until all previously issued GL commands are complete," but some simple experiments showed it returning immediately even with substantial geometry pending.
    • Is SwiftShader deferring CPU rasterization until the framebuffer is actually read (in drawImage)
  2. Why is drawImage(webglCanvas) so much slower on SwiftShader compared to hardware?

    • We observe ~10,000x slowdown (960ms vs 0.1ms) with 1m triangles
    • Is drawImage() triggering the deferred work thatfinish() didn't complete?
    • Chrome DevTools shows warnings about "GPU stalls" and readPixels during drawImage(),but why would there be GPU stalls or GPU memory reads when using a CPU-based renderer?
  3. What is the actual readback path when calling drawImage() on a WebGL canvas with SwiftShader?

    • Does it internally call readPixels() or use a different mechanism?
    • Does it need to perform MSAA resolution at this point if blitFramebuffer() was already called?

We're looking for guidance on:

  • Whether our understanding of finish() behavior in SwiftShader is correct
  • Best practices for avoiding watchdog timeouts when rendering complex scenes with SwiftShader
  • Any architectural changes we should consider for better SwiftShader compatibility

Thank you for any insights you can provide!

Reply all
Reply to author
Forward
0 new messages