Skip to content

Flutter embedder step 3b: Metal zero-copy renderer - #33

Merged
xvrh merged 6 commits into
masterfrom
claude/compassionate-jang-d030b0
May 15, 2026
Merged

Flutter embedder step 3b: Metal zero-copy renderer#33
xvrh merged 6 commits into
masterfrom
claude/compassionate-jang-d030b0

Conversation

@xvrh

@xvrh xvrh commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Step 3b of the experimental Flutter engine embedder: the out-of-process guest
switches from the software renderer to the Metal renderer, rendering
directly into shared IOSurface-backed Metal textures — a true zero-copy path
with no per-frame memcpy and no RGBA→BGRA swap.

  • Guest renderer swapFlutterRendererConfig becomes kMetal. Each ring
    IOSurface also backs an id<MTLTexture> the engine renders into via
    get_next_drawable / present_drawable. present_drawable commits an empty
    command buffer on the shared present_command_queue and sends FrameReady
    from its completion handler, so the GUI never reads a half-rendered surface.
    surface.csurface.m (Objective-C, ARC).
  • Resize on the raster thread — the surface ring is reallocated inside
    get_next_drawable when the requested size changes; at that point the engine
    holds no texture, so a resize never races an in-flight texture and no ring
    mutex is needed.
  • BGRA capture — the headless --capture-raw smoke now reads the IOSurface
    back via IOSurfaceLock; decodeRawFrame decodes BGRA.
  • The GUI side (embedded_engine.dart, protocol.dart,
    EmbedderTexturePlugin.swift) and the wire protocol are unchanged — the
    plugin already wraps the IOSurfaces as Metal-compatible CVPixelBuffers.

Design and plan: docs/superpowers/specs/2026-05-15-flutter-embedder-step3b-design.md,
docs/superpowers/plans/2026-05-15-flutter-embedder-step3b.md.

Test plan

  • flutter test test/embedder — protocol + raw-frame unit tests pass (raw-frame fixtures updated to BGRA)
  • Headless PNG smoke (dart run app/tool/embedder/run.dart) renders the scene with correct colors
  • Live-bridge assertions verified (Ready/SurfacesAllocated, 5 strictly-increasing frame IDs, resize bumps generation 0→1 and reallocates surfaces) — run via a short /tmp socket because the worktree path exceeds the macOS AF_UNIX limit
  • flutter analyze — no issues
  • Manual: run the GUI harness (flutter run -t lib/main_embedder_dev.dart -d macos …) and confirm the live scene renders, resizes, and takes pointer/keyboard input with no Metal/IOSurface console errors or tearing

🤖 Generated with Claude Code

xvrh and others added 6 commits May 15, 2026 21:36
Design for switching the out-of-process guest from the software renderer
to the Metal renderer, rendering directly into shared IOSurface-backed
Metal textures with a GPU completion fence before FrameReady.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the cross-thread retired-ring mechanism with raster-thread
reallocation inside get_next_drawable, where the engine holds no
texture. Simpler and equally correct.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The out-of-process guest now renders directly into shared
IOSurface-backed Metal textures instead of memcpy'ing software-rendered
frames. FrameReady is sent from a GPU completion-handler fence; the
surface ring is reallocated inside get_next_drawable on resize.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xvrh
xvrh merged commit 500276b into master May 15, 2026
1 check failed
@xvrh
xvrh deleted the claude/compassionate-jang-d030b0 branch May 15, 2026 21:30
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.

1 participant