Repository navigation
fix(🐛): pump an imported device's async work on the instance that owns it - #590
Merged
wcandillon merged 2 commits intoOct 23, 2026
Merged
Conversation
…s it importDevice() bound the imported device to a RuntimeContext for the shared WebGPURuntime instance. When the exporter's device lives on a different instance (react-native-skia loaded after react-native-webgpu, or any other exporter), that pump never processes the device's events and createRenderPipelineAsync, popErrorScope and mapAsync stay pending. Resolve the device's own instance through its adapter, and keep one RuntimeContext per (runtime, instance) pair so each instance has a pump.
wcandillon
approved these changes
Oct 23, 2026
…vice Follow-up to the per-(runtime, instance) RuntimeContext: - ProcessEvents() was serialized by one process-wide mutex. Pumping an imported device's instance can block on that device's own lock (Skia's Graphite device during a submit), which stalled the pumps of our own instance on other runtimes. The mutex is now per instance, resolved once per context. - getOrCreate() reads the runtimeData slot once and fills the map in a single pass; get() is gone, instance() returns a const reference and the unreachable null-instance check in importDevice is removed. - Comments and the public JSDoc no longer claim that importDevice needs the exporter to share webgpu's instance, or that native init order does not matter (on Android it decides whether Skia's instance is adopted). - ImportDevice.spec.ts imports Skia's Graphite device on the Tests screen and awaits popErrorScope, createRenderPipelineAsync, onSubmittedWorkDone and mapAsync on it. The example app installs webgpu before Skia, so on Android the device lives on a second Dawn instance: the spec hangs on the previous binding and passes with this one (verified on a Pixel 8, full suite green).
|
🎉 This PR is included in version 0.19.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
ryuhzk
added a commit
to osuki-dev/muqun-app
that referenced
this pull request
Oct 23, 2026
…drop the WebGPU patch (#151) react-native-webgpu 0.19.0 contains our upstream fix (wcandillon/react-native-webgpu#590): an imported Skia device's asynchronous work is pumped on the Dawn instance that owns it. It also contains #582, which finds Skia's Dawn instance on Android. The local patch for this is removed. react-native-skia 3.7.4 is a fix release: Canvas children render with React 19.2's reconciler, canvases share a recorder pool, and Android canvases present off the main thread. Both use Dawn 157, so the shared GPU stack stays on one copy. This changes the native fingerprint and needs a new store build.
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.
Fixes #589. Complements #582 (#581): that change makes react-native-webgpu share Skia's instance when
librnskia.sois loaded first. This one covers the case where the instances are not shared, which after #584 was closed still depends on import order on Android, and is the only case for an exporter other than Skia.Problem
importDevicebinds the imported device to the calling runtime'sRuntimeContextfor the sharedWebGPURuntimeinstance. If the device belongs to another instance, that context's pump callsProcessEvents()on the wrong instance and the device'sAllowProcessEventscallbacks never run:createRenderPipelineAsync,popErrorScopeandmapAsyncstay pending.Changes
RNWebGPU::importDevicegets the instance from the device itself (device.GetAdapter().GetInstance()) and binds the device to the context for that instance. It throws if Dawn reports no instance.RuntimeContextis now one per (JS runtime, Dawn instance) pair instead of one per runtime. The runtime data holds a map keyed byWGPUInstance;gettakes the instance;getOrCreateadds to the existing map instead of replacing the runtime data. Each context keeps its own pump, mailbox and pump counter, so the shared instance and an imported device's instance are pumped independently on the same runtime thread.processEventsMutexstays process-wide.Nothing changes when the instance is shared: there is a single map entry and
getOrCreate(runtime, _async->instance())in the request/response ops (#425) returns the same context as before. Since those call sites already pass the object's own instance, an imported device and the objects created from it keep resolving to the context of their instance on any calling runtime.Testing
Not built in this environment: I could not build Dawn or the example app here, and I did not run
yarn test. What I did run on this branch:cpplintwith the package's flags on the three files: no findings.main).clang++ -fsyntax-onlyofRuntimeContext.cppand of a translation unit includingRNWebGPU.h, against the Dawn 157.0.0 headers fromreact-native-webgpu-dawnand React Native 0.88 headers: no errors.The same change, as a patch on react-native-webgpu 0.17.0, ships in the Android app Muqun (Play preview builds) with react-native-skia 3.7.3. Its home screen imports Skia's Graphite device with
importDevice(Skia.getNativeDevice()), renders a 3D scene on it and captures React Native views withdrawElementImageToTexture. Before the patch its pipeline creation and error scopes hung when the instances were not shared; with it they settle. The diff here is that patch ported tomainwith reworded comments; the code is the same apart from line wrapping.