Version: react-native-webgpu 0.9.0, three 0.184.0 (WebGPURenderer), React Native 0.87.1 (New Architecture, Hermes), react-native-reanimated 4.6.0 / react-native-worklets 0.12.1.
Device: Android emulator Pixel_10 (API 37, arm64, -gpu host, Vulkan ranchu), NDK 27.1, minSdk 26.
What happens
A screen with one <Canvas transparent /> renders a glTF with three's WebGPURenderer (render loop via setAnimationLoop, context.present() each frame). Rendering, textures and gestures work. When the screen is popped (React Navigation native-stack) and the Canvas unmounts, the app dies with a native crash in roughly 2 out of 3 unmounts:
F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x20
dawn::native::vulkan::FencedDeleter::DeleteWhenUnused
dawn::native::vulkan::SwapChain::DetachFromSurfaceImpl
dawn::native::Surface::~Surface
com.webgpu.WebGPUView.destroy
com.webgpu.WebGPUViewManager.onDropViewInstance
The crash happens 0.1 s to 0.4 s after the React effect cleanup runs. In some runs it is preceded by I WebGPU: GPU Device Lost (Destroyed): Device was destroyed., in others there is no device-lost line at all. iOS (Metal) never crashes with the same code.
What I tried from JS, none of it changes the outcome
renderer.setAnimationLoop(null) then renderer.dispose() in the effect cleanup (baseline): crash 3/3.
- Same plus
context.unconfigure() before dispose (confirmed it executes): crash 2/3.
- Same plus keeping a strong reference to the renderer (and therefore the
GPUDevice) for 3 s after unmount, so the device cannot be collected before the native view is dropped: crash 2/3, with no "Device Lost" line, so the device was alive when Surface::~Surface ran.
Timeline of one crash (logcat, -v time), with console.warn markers from JS:
14:40:52.887 W/ReactNativeJS: MedalShowcase: cleanup start
14:40:53.312 F/libc: Fatal signal 11 (SIGSEGV) ... fault addr 0x20
Where I think it is
SurfaceInfo::~SurfaceInfo (cpp/rnwgpu/SurfaceRegistry.h) releases _surface and _pendingSurface before _texture, and it runs on the UI thread from onDropViewInstance while the JS side may still be tearing the renderer down. If a swapchain texture is still alive, or a frame is still in flight, Dawn's Vulkan swapchain detaches against state that is already gone. unconfigure() from JS only touches _surface, not _pendingSurface, which would explain why it does not help when a pending attach exists.
Repro
Any screen that mounts a Canvas, renders one frame with three's WebGPURenderer, and is popped. A minimal version is the three.js sample from the docs inside a native-stack screen; navigate in, wait for the first frame, press back, repeat a few times.
Version: react-native-webgpu 0.9.0, three 0.184.0 (WebGPURenderer), React Native 0.87.1 (New Architecture, Hermes), react-native-reanimated 4.6.0 / react-native-worklets 0.12.1.
Device: Android emulator Pixel_10 (API 37, arm64,
-gpu host, Vulkanranchu), NDK 27.1, minSdk 26.What happens
A screen with one
<Canvas transparent />renders a glTF with three'sWebGPURenderer(render loop viasetAnimationLoop,context.present()each frame). Rendering, textures and gestures work. When the screen is popped (React Navigation native-stack) and theCanvasunmounts, the app dies with a native crash in roughly 2 out of 3 unmounts:The crash happens 0.1 s to 0.4 s after the React effect cleanup runs. In some runs it is preceded by
I WebGPU: GPU Device Lost (Destroyed): Device was destroyed., in others there is no device-lost line at all. iOS (Metal) never crashes with the same code.What I tried from JS, none of it changes the outcome
renderer.setAnimationLoop(null)thenrenderer.dispose()in the effect cleanup (baseline): crash 3/3.context.unconfigure()before dispose (confirmed it executes): crash 2/3.GPUDevice) for 3 s after unmount, so the device cannot be collected before the native view is dropped: crash 2/3, with no "Device Lost" line, so the device was alive whenSurface::~Surfaceran.Timeline of one crash (logcat,
-v time), withconsole.warnmarkers from JS:Where I think it is
SurfaceInfo::~SurfaceInfo(cpp/rnwgpu/SurfaceRegistry.h) releases_surfaceand_pendingSurfacebefore_texture, and it runs on the UI thread fromonDropViewInstancewhile the JS side may still be tearing the renderer down. If a swapchain texture is still alive, or a frame is still in flight, Dawn's Vulkan swapchain detaches against state that is already gone.unconfigure()from JS only touches_surface, not_pendingSurface, which would explain why it does not help when a pending attach exists.Repro
Any screen that mounts a
Canvas, renders one frame with three'sWebGPURenderer, and is popped. A minimal version is the three.js sample from the docs inside a native-stack screen; navigate in, wait for the first frame, press back, repeat a few times.