Skip to main content

ruda_driver_wgpu/runtime/
setup.rs

1use super::*;
2
3/// A complete setup used to run wgpu.
4///
5/// These can either be created with [`init_setup`] or [`init_setup_async`].
6#[derive(Clone, Debug)]
7pub struct WgpuSetup {
8    /// The underlying wgpu instance.
9    pub instance: wgpu::Instance,
10    /// The selected 'adapter'. This corresponds to a physical device.
11    pub adapter: wgpu::Adapter,
12    /// The wgpu device Ruda will use. Nb: There can only be one device per adapter.
13    pub device: wgpu::Device,
14    /// The queue Ruda commands will be submitted to.
15    pub queue: wgpu::Queue,
16    /// The backend used by the setup.
17    pub backend: wgpu::Backend,
18}
19
20/// Create a [`WgpuDevice`] on an existing [`WgpuSetup`].
21/// Useful when you want to share a device between `Ruda` and other wgpu-dependent libraries.
22///
23/// # Note
24///
25/// Please **do not** to call on the same [`setup`](WgpuSetup) more than once.
26///
27/// This function generates a new, globally unique ID for the device every time it is called,
28/// even if called on the same device multiple times.
29pub fn init_device(setup: WgpuSetup, options: RuntimeOptions) -> WgpuDevice {
30    use core::sync::atomic::{AtomicU32, Ordering};
31
32    static COUNTER: AtomicU32 = AtomicU32::new(0);
33
34    let device_id = COUNTER.fetch_add(1, Ordering::Relaxed);
35    if device_id == u32::MAX {
36        core::panic!("Memory ID overflowed");
37    }
38
39    let device_id = WgpuDevice::Existing(device_id);
40    let server = create_server(setup, options);
41    let _ = ComputeClient::<WgpuRuntime>::init(&device_id, server);
42    device_id
43}
44
45/// Like [`init_setup_async`], but synchronous.
46/// On wasm, it is necessary to use [`init_setup_async`] instead.
47pub fn init_setup<G: GraphicsApi>(device: &WgpuDevice, options: RuntimeOptions) -> WgpuSetup {
48    cfg_if::cfg_if! {
49        if #[cfg(target_family = "wasm")] {
50            let _ = (device, options);
51            panic!("Creating a wgpu setup synchronously is unsupported on wasm. Use init_async instead");
52        } else {
53            future::block_on(init_setup_async::<G>(device, options))
54        }
55    }
56}
57
58/// Initialize a client on the given device with the given options.
59/// This function is useful to configure the runtime options
60/// or to pick a different graphics API.
61pub async fn init_setup_async<G: GraphicsApi>(
62    device: &WgpuDevice,
63    options: RuntimeOptions,
64) -> WgpuSetup {
65    let setup = create_setup_for_device(device, G::backend()).await;
66    let return_setup = setup.clone();
67    let server = create_server(setup, options);
68    let _ = ComputeClient::<WgpuRuntime>::init(device, server);
69    return_setup
70}
71
72/// Select the wgpu device and queue based on the provided [device](WgpuDevice) and
73/// [backend](wgpu::Backend).
74pub(crate) async fn create_setup_for_device(
75    device: &WgpuDevice,
76    backend: wgpu::Backend,
77) -> WgpuSetup {
78    let (instance, adapter) = super::adapters::request_adapter(device, backend).await;
79    let (device, queue) = backend::request_device(&adapter).await;
80
81    log::info!(
82        "Created wgpu compute server on device {:?} => {:?}",
83        device,
84        adapter.get_info()
85    );
86
87    WgpuSetup {
88        instance,
89        adapter,
90        device,
91        queue,
92        backend,
93    }
94}