Skip to content

perf(web-ui): use ResizeObserver for canvas sizing#621

Merged
stackia merged 2 commits into
mainfrom
perf/resize-observer-canvas-sizing
Jul 5, 2026
Merged

perf(web-ui): use ResizeObserver for canvas sizing#621
stackia merged 2 commits into
mainfrom
perf/resize-observer-canvas-sizing

Conversation

@stackia

@stackia stackia commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • desiredEnhancedCanvasSize() called getBoundingClientRect() on the canvas's ancestor chain every decoded frame to compute the WebGL backing-store size, forcing a synchronous layout on the hot render path (up to 60fps, across both double-buffered renderer slots).
  • Replaced with a ResizeObserver on the stable aspect-video container, caching the size in device pixels. The per-frame path now just reads the cache plus a cheap isConnected/ownerDocument check — no layout, no getBoundingClientRect.
  • Prefers devicePixelContentBoxSize for exact device pixels (auto-tracks DPR changes, e.g. moving windows across monitors), falling back to CSS content box × clamped DPR for engines that don't support it.
  • The observer is realm-aware: it's recreated in the target's own window when the owning document changes, since Document Picture-in-Picture re-parents the whole player surface into a separate window/document, which would otherwise leave a stale observer behind.
  • Backing-store size behavior (clamped to [source, min(source×2, 1920×1088)]) is unchanged.

Test plan

  • pnpm tsc --noEmit and pnpm biome check pass
  • Verified locally with devlab mock streams + Chrome DevTools: video plays and canvas sizes correctly on load
  • Resizing the browser window updates canvas sharpness/size (up and down)
  • Channel switching (double-buffered a/b slots) sizes the newly shown slot correctly on first frame
  • No console errors related to ResizeObserver or the renderer

…me getBoundingClientRect

desiredEnhancedCanvasSize() called getBoundingClientRect() every decoded
frame to size the WebGL backing store, forcing a synchronous layout on
the hot render path. Cache the size in device pixels via ResizeObserver
instead, re-observing only when the target detaches or moves to a
different document (Document Picture-in-Picture re-parents the player
surface into a floating window).
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Documentation preview

The documentation preview has been deployed for this pull request.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79487937f2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web-ui/src/mpegts/render/renderer.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the Web UI video renderer’s canvas backing-store sizing by removing a per-frame synchronous layout dependency and replacing it with a cached, observer-driven size in device pixels (including support for Document Picture-in-Picture re-parenting).

Changes:

  • Replaces per-frame ancestor getBoundingClientRect() scanning with a ResizeObserver attached to a stable sized ancestor, caching the latest device-pixel size.
  • Adds realm-aware observer management so the observer is recreated when the canvas is moved across documents (e.g., Document Picture-in-Picture).
  • Seeds cached size synchronously to keep the first enhanced frame correctly sized before observer callbacks fire.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web-ui/src/mpegts/render/renderer.ts
Comment thread web-ui/src/mpegts/render/renderer.ts Outdated
The observed element and the canvas move into the Document Picture-in-
Picture window together, so comparing their ownerDocuments could never
detect the re-parent and the observer built in the original window went
stale. Track the observer's own document instead and recreate it in the
target's window when they diverge.

Drop the CSS-content-box x DPR fallback: device-pixel-content-box is
supported across all target browsers, so read device pixels directly.
@stackia stackia merged commit e2d0f74 into main Jul 5, 2026
9 of 10 checks passed
@stackia stackia deleted the perf/resize-observer-canvas-sizing branch July 5, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants