Skip to content

v0.3.0 rebind works but swapchain content never composites (gray window) #3

Description

@nikolas-beckel

First off — thanks for the incredibly fast turnaround on perry#5812 (perry PR #5814 + webgpu v0.3.0) and for the credit. I retested today with a completely unpatched setup and want to report what works and what still doesn't on my hardware.

Full disclosure: I ran this retest with AI assistance (Claude Code drove the builds, instrumented runs, and window captures). All evidence below — diag logs, DWM captures, hang repros — comes from real runs on my machine, but the diagnosis was AI-supported, so treat the interpretation with the usual skepticism and I'm happy to re-verify anything manually.

Setup

  • Windows 11 Pro 10.0.26200, 3 × 1920×1080 monitors, 100% DPI scaling (AppliedDPI 96 — so perry#5884 shouldn't apply here)
  • NVIDIA GeForce GTX 1080, driver 32.0.15.6603, wgpu backend d3d12
  • perry built from main (post-#5814), @perryts/webgpu 0.3.0 from npm, zero local patches
  • Test app: the perry#5812 triangle repro (BloomView + surface-first ordering, 15-frame burst, explicit trailing args)

Confirmed fixed ✅

  1. Item 1 (lib name): links out of the box, no manifest patch needed (library_search.rs translation works).

  2. Item 2 (link libs): no LNK2019, both the manifest libs and the auto-link path cover it.

  3. Item 3 (compatible surface): requestAdapter(surface) picks a presentation-capable adapter; surfaceConfigure succeeds on d3d12.

  4. Item 5 partially — the mount-aware rebind fires exactly as designed. PERRY_WEBGPU_DIAG=1 log:

    surfaceFromNativeView: hwnd=0x2f08ba visible=0 parent=0x3108aa root=0x3108aa rect=(8,31)-(808,631)
    surfaceConfigure:      hwnd=0x2f08ba visible=0 parent=0x3108aa root=0x3108aa rect=(8,31)-(808,631)
    getCurrentTexture: window reparented — rebinding: hwnd=0x2f08ba visible=1 parent=0x6091c root=0x6091c rect=(34,57)-(818,618)
    getCurrentTexture: swapchain recreated: hwnd=0x2f08ba visible=1 parent=0x6091c root=0x6091c rect=(34,57)-(818,618)
    surfacePresent × 15:   hwnd=0x2f08ba visible=1 parent=0x6091c root=0x6091c
    

(Item 4 / ABI padding: not yet re-tested with omitted args — I kept the explicit-args variant to isolate variables; will test once the display issue below is resolved.)

Still broken here ❌ — window stays gray despite correct rebind + presents

After the rebind, all 15 presents go to the visible child under the correct top-level ancestor — but the client area stays uniformly gray. To rule out screenshot artifacts I captured the window through a DWM live thumbnail (DwmRegisterThumbnail, i.e. the actual composition), plus PrintWindow(PW_RENDERFULLCONTENT) on both the top-level and the BloomView child HWND: all show a uniform gray client area — not even the render pass's near-black clear color (0.07, 0.07, 0.09) arrives. So on this box the swapchain content never enters DWM composition even after the rebind.

In other words: this looks like the exact failure mode the README's Windows notes call out — "on some driver/DWM combinations a swapchain created under the parking window never composites even after the mount" — except here the surface-recreate-after-reparent does not recover it. The swapchain is demonstrably rebuilt against the visible window tree (diag above) and still never composites.

Note that the test app follows the README's recommended main-thread pattern (short burst, then stop re-registering onFrame); after the burst no "last presented frame" stays on screen either — just gray.

Since you can see content on your machine (perry#5884, clipped due to DPI), this looks hardware/setup-dependent. Differences that might matter: multi-monitor (3 displays), NVIDIA driver (GTX 1080, 32.0.15.6603), Win11 build 26200.

Follow-up effect: any continuous render loop hard-hangs the app

This matches the (very helpful) comment in js_webgpu_surface_get_current_texture: when DWM doesn't consume presents, the swapchain queue fills after ~buffer-count + frame-latency frames and the next acquire blocks the main thread forever → window ghosts ("not responding"). Reproduced here:

  • 15-frame burst: barely survives, app becomes responsive again afterwards (but gray).
  • Continuous onFrame loop: hangs after ~10 frames. Also hangs when throttled to every 4th tick, and also with presentMode: "immediate" — so it's the acquire, not the vsync-blocking present.

A defensive improvement independent of the composition bug: acquiring with a timeout (or checking Surface::get_current_texture for Timeout / re-checking visibility) would turn the permanent main-thread hang into a recoverable "not presentable" (0) result, same contract as the visibility gate.

Happy to test any diagnostic build or patch on this machine — it seems to be a useful worst-case box for this feature.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions