1#[derive(Debug, Clone)]
10pub struct GpuDeviceInfo {
11 pub name: String,
13 pub backend: String,
15 pub device_type: String,
17}
18
19pub struct GpuContext {
29 #[cfg(feature = "gpu")]
30 pub(crate) device: wgpu::Device,
31 #[cfg(feature = "gpu")]
32 pub(crate) queue: wgpu::Queue,
33 _private: (),
35}
36
37impl GpuContext {
38 pub fn try_init() -> Option<Self> {
45 #[cfg(feature = "gpu")]
46 {
47 pollster::block_on(Self::try_init_async())
48 }
49 #[cfg(not(feature = "gpu"))]
50 {
51 None
52 }
53 }
54
55 #[cfg(feature = "gpu")]
57 async fn try_init_async() -> Option<Self> {
58 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
59 backends: wgpu::Backends::all(),
60 ..wgpu::InstanceDescriptor::new_without_display_handle()
61 });
62
63 let adapter = instance
64 .request_adapter(&wgpu::RequestAdapterOptions {
65 power_preference: wgpu::PowerPreference::HighPerformance,
66 compatible_surface: None,
67 force_fallback_adapter: false,
68 })
69 .await
70 .ok()?;
71
72 let (device, queue) = adapter
73 .request_device(&wgpu::DeviceDescriptor::default())
74 .await
75 .ok()?;
76
77 Some(GpuContext {
78 device,
79 queue,
80 _private: (),
81 })
82 }
83
84 pub fn enumerate_devices() -> Vec<GpuDeviceInfo> {
86 #[cfg(feature = "gpu")]
87 {
88 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
89 backends: wgpu::Backends::all(),
90 ..wgpu::InstanceDescriptor::new_without_display_handle()
91 });
92
93 pollster::block_on(instance.enumerate_adapters(wgpu::Backends::all()))
94 .into_iter()
95 .map(|adapter| {
96 let info = adapter.get_info();
97 GpuDeviceInfo {
98 name: info.name,
99 backend: format!("{:?}", info.backend),
100 device_type: format!("{:?}", info.device_type),
101 }
102 })
103 .collect()
104 }
105 #[cfg(not(feature = "gpu"))]
106 {
107 Vec::new()
108 }
109 }
110
111 pub fn try_init_with_name(name_pattern: &str) -> Option<Self> {
114 #[cfg(feature = "gpu")]
115 {
116 pollster::block_on(Self::try_init_with_name_async(name_pattern))
117 }
118 #[cfg(not(feature = "gpu"))]
119 {
120 let _ = name_pattern;
121 None
122 }
123 }
124
125 #[cfg(feature = "gpu")]
127 async fn try_init_with_name_async(name_pattern: &str) -> Option<Self> {
128 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
129 backends: wgpu::Backends::all(),
130 ..wgpu::InstanceDescriptor::new_without_display_handle()
131 });
132
133 let pattern_lower = name_pattern.to_lowercase();
134 let adapter = instance
135 .enumerate_adapters(wgpu::Backends::all())
136 .await
137 .into_iter()
138 .find(|a| a.get_info().name.to_lowercase().contains(&pattern_lower))?;
139
140 let (device, queue) = adapter
141 .request_device(&wgpu::DeviceDescriptor::default())
142 .await
143 .ok()?;
144
145 Some(GpuContext {
146 device,
147 queue,
148 _private: (),
149 })
150 }
151
152 pub fn try_init_with_index(index: usize) -> Option<Self> {
154 #[cfg(feature = "gpu")]
155 {
156 pollster::block_on(Self::try_init_with_index_async(index))
157 }
158 #[cfg(not(feature = "gpu"))]
159 {
160 let _ = index;
161 None
162 }
163 }
164
165 #[cfg(feature = "gpu")]
167 async fn try_init_with_index_async(index: usize) -> Option<Self> {
168 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
169 backends: wgpu::Backends::all(),
170 ..wgpu::InstanceDescriptor::new_without_display_handle()
171 });
172
173 let adapters: Vec<_> = instance
174 .enumerate_adapters(wgpu::Backends::all())
175 .await
176 .into_iter()
177 .collect();
178
179 let adapter = adapters.into_iter().nth(index)?;
180
181 let (device, queue) = adapter
182 .request_device(&wgpu::DeviceDescriptor::default())
183 .await
184 .ok()?;
185
186 Some(GpuContext {
187 device,
188 queue,
189 _private: (),
190 })
191 }
192}