Skip to content

Consolidate device management and add device-lost recovery in reactor/direct2d sample#4563

Open
damyanp wants to merge 4 commits into
microsoft:masterfrom
damyanp:device_management
Open

Consolidate device management and add device-lost recovery in reactor/direct2d sample#4563
damyanp wants to merge 4 commits into
microsoft:masterfrom
damyanp:device_management

Conversation

@damyanp

@damyanp damyanp commented Jun 11, 2026

Copy link
Copy Markdown
Member

Consolidates GPU device management in the reactor direct2d sample so a single shared D3D11 + Direct2D device is shared across all samples, and adds device-lost recovery.

What changed

Shared device (Part 1)

  • New device module: SharedDevice (agile COM, MULTI_THREADED D2D factory) and Device (Rc, ptr-eq identity), exposed through a reactor Gpu context via gpu_context().
  • Both samples (swap_chain, surface_image_source) now draw from the same device instead of each creating their own.

Device-lost recovery (Part 2)

  • Gpu carries the device plus a recovery Updater. The app root (shell) owns the device and a recover_gen counter; a single effect keyed on recover_gen recreates the shared device on every request_recovery() (and on initial mount).
  • is_device_lost matches Win2D's set of device-lost codes (the five DXGI removal codes plus D2DERR_RECREATE_TARGET). Samples call gpu.request_recovery() on any such error; recovery always recreates the device (no local-recreate / health-check gate).
  • A "Recreate Device" test button under the NavigationView triggers the same path for manual testing.

Worker plumbing

  • The swap_chain worker-thread plumbing (panel ref, swap-chain async state, render thread, spawn dedup, device-loss token marshalling, effects) is extracted into a use_render_host hook with mount/unmount/resize, leaving swap_chain_sample lean. Device loss detected on the worker is marshalled to the UI thread (the Updater is not Send) before triggering recovery.

Testing

  • cargo build/clippy/fmt clean for reactor_direct2d.
  • Ran the sample: switching between samples, resizing, and the "Recreate Device" button all recover correctly.

damyanp and others added 4 commits June 11, 2026 07:49
Create the D3D11 + Direct2D device once and share it across every sample via
the reactor DEVICE context, instead of each sample creating its own device.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Recreate the shared GPU device when a sample reports a device-lost
error. The shared Device and a recovery signal are bundled into a single
Gpu context; samples call request_recovery() on device loss, which bumps
a counter in the shell that recreates the device. A Recreate Device test
button exercises the same path on demand.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Condense the verbose render-thread doc comments to a terser style.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the render-worker plumbing (panel handle, swap-chain attach, respawn
dedup, device-loss marshalling, and the related effects) out of the sample
component into a use_render_host hook returning a RenderHost handle, so the
sample reads as just circle-count state, buttons, and layout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Consolidates GPU device management in the reactor_direct2d sample by introducing an app-wide shared D3D11/D2D device exposed via a Gpu context, and wires device-lost recovery so samples can request a full device recreation from the root.

Changes:

  • Added a shared Device/SharedDevice + Gpu context (and is_device_lost) to centralize D3D/D2D/DXGI ownership.
  • Refactored the swap-chain sample to run its worker using the shared device and marshal device-lost back to the UI thread.
  • Updated the SurfaceImageSource sample and the shell to rebuild resources when the shared device is recreated.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
crates/samples/reactor/direct2d/src/device.rs Introduces shared device types, GPU context plumbing, and device-lost classification helper.
crates/samples/reactor/direct2d/src/swap_chain.rs Uses shared device, adds device-lost notification path, and extracts worker lifecycle into a hook/host.
crates/samples/reactor/direct2d/src/surface_image_source.rs Rebuilds the SurfaceImageSource using the shared device and requests recovery on device-lost errors.
crates/samples/reactor/direct2d/src/shell.rs Owns shared device + recovery signal, provides Gpu context, and adds a manual “Recreate Device” UI action.
crates/samples/reactor/direct2d/src/main.rs Registers the new device module.

Comment on lines +36 to +37
// SAFETY: every interface held here is an agile (free-threaded) COM object.
unsafe impl Send for SharedDevice {}
Comment on lines 54 to 57
#[derive(Clone, PartialEq)]
pub struct SendSwap(IDXGISwapChain1);

unsafe impl Send for SendSwap {}
Comment on lines +126 to +128
/// What every sample needs from the root: the shared [`Device`] (`None` until
/// created, and briefly during recreation) and a way to request recovery.
#[derive(Clone, PartialEq)]
Self { device, recover }
}

/// The shared device, or `None` while it is being (re)created.
Comment on lines +58 to +70
// Test aid: recreate the shared device on demand, without a real GPU
// device-removal event.
let recreate_device = {
move || {
update_device.call(|current| match Device::new() {
Ok(d) => Some(d),
Err(e) => {
eprintln!("failed to recreate shared device: {e}");
current
}
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants