Add WindowRenderer::resume_async for WASM-friendly wgpu init#59
Open
tonybierman wants to merge 2 commits intoDioxusLabs:mainfrom
Open
Add WindowRenderer::resume_async for WASM-friendly wgpu init#59tonybierman wants to merge 2 commits intoDioxusLabs:mainfrom
tonybierman wants to merge 2 commits intoDioxusLabs:mainfrom
Conversation
Author
|
@nicoburns request review. This is antecedent to a blitz PR after its merged. Could arguably bump the AnyRender version. |
Member
|
@tonybierman Would it be possible to get both PRs together? I'd like to actually run them as part of the review process. Just from looking at this, it seems to me like this ought not to be usable in |
wgpu adapter/device/surface initialization is fundamentally async on
the web, so calling pollster::block_on in the synchronous resume path
deadlocks the JS event loop on wasm32-unknown-unknown. Reworks the
WindowRenderer trait to take an `on_ready` callback in `resume` and
split finalization into a new `complete_resume`:
fn resume<F: FnOnce() + 'static>(
&mut self, window, width, height, on_ready: F,
);
fn complete_resume(&mut self) -> bool { true }
GPU backends (anyrender_vello, anyrender_vello_hybrid) spawn the wgpu
init future via wasm_bindgen_futures::spawn_local on wasm and
pollster::block_on on native, deliver the surface back through a
futures-channel oneshot, and transition Pending → Active inside
complete_resume. The synchronous backends (null, skia, pixels,
softbuffer) call on_ready() inline at the end of resume and inherit
the default complete_resume that returns `true`.
This is a breaking change to the WindowRenderer trait: downstream
impls must update the `resume` signature. `complete_resume` picks up
the trait default unless the backend has its own async init.
Refs: DioxusLabs/blitz#160
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
57c17f7 to
8b08a5e
Compare
Address code-review feedback on the callback + complete_resume redesign:
- Remove the `complete_resume` default body. Forgetting to override on an
async-init backend would silently no-op rendering; an explicit impl is
required. Trivial backends (null, skia, pixels, softbuffer) get
`fn complete_resume(&mut self) -> bool { true }`.
- Add `WindowRenderer::is_pending()` so callers can distinguish suspended
from initializing without depending on `is_active()` going through false
during the wasm async window.
- Restructure RenderState in vello + vello_hybrid as
`Suspended { wgpu_context } | Pending { receiver } | Active { wgpu_context, active }`.
The previous shape kept `wgpu_context: Option<WGPUContext>` as a struct
field and an `Active(ActiveRenderState)` variant, which made
`Active(_) + wgpu_context: None` representable. The new shape moves
ownership through `mem::replace` so the in-flight init can take the
context, then return it on success.
- Add `debug_assert!` in `resume` against non-Suspended state — calling
resume while Pending or Active orphans the in-flight context and pays
for a fresh adapter+device init on the fallback path.
- Re-resume custom paint sources inside `complete_resume` rather than
inside the spawned future, so `CustomPaintSource` doesn't need to be
`Send`.
- Doc the `spawn_init` cfg helper, fix `errorss` typo, drop a redundant
`let mut wgpu_context = wgpu_context` rebind, and tighten a few
comments that drifted from the new design.
- Update bunnymark example to the new resume signature.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tonybierman
added a commit
to tonybierman/blitz
that referenced
this pull request
May 9, 2026
Replace the View::resume_async + BlitzWasmApplication approach with the unified callback/event design landed in DioxusLabs/anyrender#59. The same BlitzApplication driver now runs on native and wasm32; there is no async fn in the WindowRenderer trait and no parallel wasm event loop. Removed: - BlitzWasmApplication and the wasm-only re-export (the slot/Rc<RefCell> pattern that user code had to participate in). - View::resume_async. - wasm-bindgen-futures dep from blitz-shell (renderers own spawn_local now). Added: - BlitzShellEvent::ResumeReady { window_id } variant. - View::resume now passes a callback that dispatches ResumeReady through the proxy. Native targets call the callback inline (pollster::block_on inside the renderer); wasm32 dispatches it later from the JS microtask queue. - View::complete_resume re-resolves the doc, syncs the renderer to the current viewport size (resize/scale events that arrived while Pending were no-ops on the renderer), paints the first frame, and installs the doc poll waker. - BlitzApplication::handle_blitz_shell_event handles ResumeReady by calling view.complete_resume. - DioxusNativeWindowRenderer wrapper forwards the new resume(.., on_ready) signature and complete_resume / is_pending to the inner renderer. Example: - examples/wasm_hello now drives BlitzApplication directly, mirroring the native pattern. The wasm-specific code is just bundled-font setup, canvas attach, surface seed size, then run_app. The [patch.crates-io] block points at the AnyRender PR branch and will be removed once that PR merges and anyrender is released to crates.io. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tonybierman
added a commit
to tonybierman/blitz
that referenced
this pull request
May 9, 2026
wgpu adapter/device/surface init is fundamentally async on the web, so the existing synchronous View::resume path (which calls WindowRenderer::resume → pollster::block_on) deadlocks the JS event loop on wasm32-unknown-unknown. Implements the unified design discussed on DioxusLabs/anyrender#59: the renderer's `resume` takes an `on_ready: F` callback and an extra `complete_resume` finalize step; on wasm32 the renderer drives wgpu init via `wasm_bindgen_futures::spawn_local` and signals readiness through a new `BlitzShellEvent::ResumeReady` variant that the embedder handles via the existing event loop. The same code path runs on native and wasm — no `View::resume_async`, no parallel `BlitzWasmApplication`, no slot/`Rc<RefCell>` pattern in user code, no `async fn` in the WindowRenderer trait. blitz-shell: - BlitzShellEvent::ResumeReady { window_id } variant. - View::resume passes a callback that dispatches ResumeReady through the proxy. Native targets call it inline (pollster::block_on inside the renderer); wasm32 dispatches it later from the JS microtask queue. - View::complete_resume re-resolves the doc, syncs the renderer to the current viewport size (resize/scale events that arrived while Pending were no-ops on the renderer), paints the first frame, and installs the doc poll waker. - BlitzApplication handles ResumeReady by calling view.complete_resume. - DioxusNativeWindowRenderer wrapper forwards the new resume(.., on_ready) signature plus complete_resume / is_pending. - Drop wasm-bindgen-futures from blitz-shell — renderers own spawn_local now. - web-time as a drop-in for std::time::Instant on wasm32. examples/wasm_hello: minimal Trunk-served demo driving BlitzApplication directly, mirroring the native pattern. The [patch.crates-io] block points at the AnyRender PR branch and will be removed once that PR merges and anyrender is released to crates.io. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an async
resume_asyncmethod toWindowRendererso GPU backends can drive wgpu's fundamentally-async surface initialization withoutpollster::block_ondeadlocking the JS event loop onwasm32-unknown-unknown. The default body forwards to syncresume(non-breaking for downstream impls);anyrender_velloandanyrender_vello_hybridoverride it with a real async body and nowpanic!from syncresumeon wasm32 instead of silently deadlocking.