CNA-GAP-064: WEBGPU does not propagate a real device loss: OnDeviceLost only logs, so DeviceLost, the device status and the draw gate react only to the debug hooks
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
WebGPURenderer sets its lost flag, closes CanBeginDrawEXT() and raises DeviceLost only inside DebugSimulateContextLoss; the callback registered for a real loss only writes to stderr. CNA's own plan (WEBGPU-182) records the driver-reported path as not done and unverified, so this is an incomplete feature rather than a broken contract.
- Identifier
CNA-GAP-064- Category
- Functional gap
- Subsystem
- Graphics & renderers
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- GraphicsDevice::DeviceLost / DeviceReset, getGraphicsDeviceStatusProperty() and the CanBeginDrawEXT() gate behind GraphicsDeviceManager::BeginDraw, on the WEBGPU renderer
Expected behaviour
XNA raises DeviceLost and reports GraphicsDeviceStatus::Lost when the device is lost, and DirectX 9, 11 and 12, Direct2D and Vulkan raise it from their real error paths through GraphicsRendererCreateArgs::deviceEventCallback. That channel is opt-in, though, and for WEBGPU nothing documented promises a real loss reaches it: webgpu-renderer.md describes recovery through the debug hooks only, and plan_webgpu.md WEBGPU-182 closes with 'what is NOT done is the driver-reported path'. The same document adds a WebGPU-specific rule: a lost device must be gated before the acquire, because wgpuSurfaceGetCurrentTexture on a surface whose device is lost panics inside wgpu-native and aborts the process, and CanBeginDrawEXT() returning false is what stands between a lost device and that abort.
Actual behaviour at TARGET
RequestDeviceOnlyEXT (also reached through RequestAdapterAndDevice) registers the free function OnDeviceLost as deviceLostCallbackInfo.callback with no user data. OnDeviceLost prints "CNA WebGPU device lost (...)" to stderr and does nothing else; without a renderer pointer it cannot set deviceLost_, raise RendererDeviceEvent::Lost or close CanBeginDrawEXT() (which returns !deviceLost_). The only code that does those things is WebGPURenderer::DebugSimulateContextLoss, and the only recovery is DebugRestoreContext; both are debug hooks the renderer never calls itself. When a real loss reaches the callback, the game receives no DeviceLost, GraphicsDeviceStatus stays Normal, BeginDraw keeps returning true and the renderer continues its frame loop against the lost device; nothing rebuilds it. The header comment of DebugSimulateContextLoss says the callback 'stays wired for a real driver-reported loss', which overstates what the callback does.
Source locations
modules/renderers/webgpu/src/WebGPURenderer.cpp— OnDeviceLost (logs only) and its registration in WebGPURenderer::RequestDeviceOnlyEXTmodules/renderers/webgpu/src/WebGPURenderer.cpp— WebGPURenderer::DebugSimulateContextLoss and DebugRestoreContext, the only places deviceLost_ changes and Lost/Reset are raisedmodules/renderers/webgpu/include/CNA/Internal/Renderers/WebGPU/WebGPURenderer.hpp— CanBeginDrawEXT returns !deviceLost_docs/webgpu-renderer.md— Device loss: what the pin actually does (WEBGPU-180) and the device-loss gate (WEBGPU-181)modules/renderers/webgpu/examples/webgpu_context_recovery_test.cpp— recovery evidence drives the debug hooks only
Evidence
Checked by reading at 009d40f5; not executed. That the callback propagates nothing is certain from the code. How often a real loss reaches it is not: natively, CNA measured that the pinned wgpu-native v29.0.1.1 delivers no device-lost callback for an application-initiated destroy (WEBGPU-180), and whether a driver-reported loss delivers one was not measured; in a browser, CNA states that the callback fires but derived that from the emdawnwebgpu port's JavaScript without a browser confirmation. What the browser does with the renderer's continued calls on a lost device was not established here. Natively, if a later pin does deliver the callback, the open gate leaves exactly the acquire path CNA measured to abort the process.
Focused reproduction
// Illustrative; not compiled or run for this entry. Web target (emdawnwebgpu), where CNA states the
// device-lost callback fires. Destroy the device from outside the renderer's debug hook:
wgpuDeviceDestroy(webGpuRenderer.Device());
// Expected: DeviceLost raised, GraphicsDeviceStatus == Lost, CanBeginDrawEXT() == false.
// Actual per the code: one "CNA WebGPU device lost (...)" line on stderr; status stays Normal and the
// next BeginDraw proceeds.
Current tests
webgpu_context_recovery_test.cpp verifies the debug-hook path end to end (the gate goes false and back, each event fires once, resources survive). No test delivers a device-lost callback or asserts that one reaches GraphicsDevice.
Regression test
Pass the renderer as the callback's userdata1 and have it set deviceLost_ and raise RendererDeviceEvent::Lost (ignoring the loss CNA itself causes in DebugSimulateContextLoss); then a browser test in the WEBGPU-196 style that destroys the device from outside the renderer and asserts that DeviceLost fired and CanBeginDrawEXT() is false.
Blast radius
WEBGPU only, most visibly on the web target. Games that rely on DeviceLost, DeviceReset or GraphicsDeviceStatus to pause, save or rebuild never hear of a real loss, and the renderer keeps drawing against a dead device. DirectX 9, 11 and 12, Direct2D and Vulkan raise Lost from their own real error paths and are unaffected.
Workaround
No workaround is known.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Graphics renderers: modern GPU renderers
- Architecture
- Graphics architecture: device loss
- Known issues
- Functional gap index