1use sim_lib_compute_auto::{ComputeDeviceIdentity, ComputeEvidenceKind, ComputePhysicalEvidence};
4use wgpu::{Backends, Features, Limits};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct RequestedWgpuProfile {
9 pub limits: WgpuLimitEvidence,
11 pub timestamp_query: bool,
13 pub shader_f16: bool,
15}
16
17impl RequestedWgpuProfile {
18 pub fn from_parts(limits: Limits, features: Features) -> Self {
20 Self {
21 limits: WgpuLimitEvidence::from_limits(&limits),
22 timestamp_query: features.contains(Features::TIMESTAMP_QUERY),
23 shader_f16: features.contains(Features::SHADER_F16),
24 }
25 }
26}
27
28#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct WgpuLimitEvidence {
31 pub max_buffer_size: u64,
33 pub max_storage_buffer_binding_size: u64,
35 pub max_uniform_buffer_binding_size: u64,
37 pub min_storage_buffer_offset_alignment: u32,
39 pub min_uniform_buffer_offset_alignment: u32,
41 pub max_compute_workgroups_per_dimension: u32,
43 pub max_compute_invocations_per_workgroup: u32,
45 pub max_compute_workgroup_size_x: u32,
47 pub max_compute_workgroup_size_y: u32,
49 pub max_compute_workgroup_size_z: u32,
51}
52
53impl WgpuLimitEvidence {
54 pub fn from_limits(limits: &Limits) -> Self {
56 Self {
57 max_buffer_size: limits.max_buffer_size,
58 max_storage_buffer_binding_size: limits.max_storage_buffer_binding_size,
59 max_uniform_buffer_binding_size: limits.max_uniform_buffer_binding_size,
60 min_storage_buffer_offset_alignment: limits.min_storage_buffer_offset_alignment,
61 min_uniform_buffer_offset_alignment: limits.min_uniform_buffer_offset_alignment,
62 max_compute_workgroups_per_dimension: limits.max_compute_workgroups_per_dimension,
63 max_compute_invocations_per_workgroup: limits.max_compute_invocations_per_workgroup,
64 max_compute_workgroup_size_x: limits.max_compute_workgroup_size_x,
65 max_compute_workgroup_size_y: limits.max_compute_workgroup_size_y,
66 max_compute_workgroup_size_z: limits.max_compute_workgroup_size_z,
67 }
68 }
69}
70
71#[derive(Clone, Debug, PartialEq, Eq)]
73pub struct WgpuCapabilityEvidence {
74 pub timestamp_query: bool,
76 pub shader_f16: bool,
78 pub mappable_primary_buffers: bool,
80}
81
82impl WgpuCapabilityEvidence {
83 pub fn from_features(features: Features) -> Self {
85 Self {
86 timestamp_query: features.contains(Features::TIMESTAMP_QUERY),
87 shader_f16: features.contains(Features::SHADER_F16),
88 mappable_primary_buffers: features.contains(Features::MAPPABLE_PRIMARY_BUFFERS),
89 }
90 }
91}
92
93#[derive(Clone, Debug, PartialEq, Eq)]
95pub struct WgpuAdapterEvidence {
96 pub ordinal: usize,
98 pub name: String,
100 pub backend: String,
102 pub adapter_type: String,
104 pub vendor: u32,
106 pub device: u32,
108 pub requested: RequestedWgpuProfile,
110 pub granted_limits: WgpuLimitEvidence,
112 pub granted_features: WgpuCapabilityEvidence,
114}
115
116impl WgpuAdapterEvidence {
117 pub fn sort_key(&self) -> (&str, &str, &str, u32, u32) {
120 (
121 self.backend.as_str(),
122 self.adapter_type.as_str(),
123 self.name.as_str(),
124 self.vendor,
125 self.device,
126 )
127 }
128}
129
130#[derive(Clone, Debug, PartialEq, Eq)]
132pub struct TransferEvidence {
133 pub bytes: u64,
135 pub transfer_ok: bool,
137 pub mapping_ok: bool,
139}
140
141#[derive(Clone, Debug, PartialEq, Eq)]
143pub struct AllocationAttempt {
144 pub bytes: u64,
146 pub success: bool,
148}
149
150#[derive(Clone, Debug, PartialEq, Eq)]
152pub struct ProbeEvidence {
153 pub transfer: TransferEvidence,
155 pub allocation_attempts: Vec<AllocationAttempt>,
157}
158
159impl ProbeEvidence {
160 pub fn successful(&self) -> bool {
162 self.transfer.transfer_ok
163 && self.transfer.mapping_ok
164 && self
165 .allocation_attempts
166 .iter()
167 .any(|attempt| attempt.success && attempt.bytes > 0)
168 }
169}
170
171#[derive(Clone, Debug, PartialEq, Eq)]
173pub struct WgpuAdapterProbe {
174 pub evidence_kind: ComputeEvidenceKind,
176 pub claimed_identity: Option<ComputeDeviceIdentity>,
178 pub observed_identity: Option<ComputeDeviceIdentity>,
180 pub adapter: WgpuAdapterEvidence,
182 pub probe: ProbeEvidence,
184}
185
186pub struct WgpuAdapterRuntime {
188 pub(crate) probe: WgpuAdapterProbe,
189 pub(crate) device: wgpu::Device,
190 pub(crate) queue: wgpu::Queue,
191}
192
193impl WgpuAdapterRuntime {
194 pub fn new(probe: WgpuAdapterProbe, device: wgpu::Device, queue: wgpu::Queue) -> Self {
197 Self {
198 probe,
199 device,
200 queue,
201 }
202 }
203
204 pub fn probe(&self) -> &WgpuAdapterProbe {
206 &self.probe
207 }
208}
209
210pub trait WgpuProbePort {
212 fn probe_wgpu(
214 &self,
215 policy: &ProbePolicy,
216 ) -> Result<Vec<WgpuAdapterRuntime>, WgpuDiscoveryError>;
217}
218
219impl ComputePhysicalEvidence for WgpuAdapterProbe {
220 fn evidence_kind(&self) -> ComputeEvidenceKind {
221 self.evidence_kind
222 }
223
224 fn claimed_identity(&self) -> Option<&ComputeDeviceIdentity> {
225 self.claimed_identity.as_ref()
226 }
227
228 fn observed_identity(&self) -> Option<&ComputeDeviceIdentity> {
229 self.observed_identity.as_ref()
230 }
231}
232
233#[derive(Clone, Debug, Default, PartialEq, Eq)]
235pub struct WgpuDiscovery {
236 pub adapters: Vec<WgpuAdapterProbe>,
238 pub diagnostics: Vec<String>,
240}
241
242impl WgpuDiscovery {
243 pub fn from_probes(probes: Vec<WgpuAdapterProbe>, mut diagnostics: Vec<String>) -> Self {
246 let mut adapters = Vec::new();
247 for probe in probes {
248 if probe.probe.successful() {
249 adapters.push(probe);
250 } else {
251 diagnostics.push(format!(
252 "wgpu adapter {} did not pass required probes",
253 probe.adapter.name
254 ));
255 }
256 }
257 adapters.sort_by(|left, right| left.adapter.sort_key().cmp(&right.adapter.sort_key()));
258 for (ordinal, probe) in adapters.iter_mut().enumerate() {
259 probe.adapter.ordinal = ordinal;
260 }
261 Self {
262 adapters,
263 diagnostics,
264 }
265 }
266}
267
268#[derive(Clone, Debug, PartialEq, Eq)]
270pub struct ProbePolicy {
271 pub backends: Backends,
273 pub transfer_bytes: u64,
275 pub max_allocation_probe_bytes: u64,
277}
278
279impl Default for ProbePolicy {
280 fn default() -> Self {
281 Self {
282 backends: Backends::all(),
283 transfer_bytes: 16,
284 max_allocation_probe_bytes: 16 * 1024 * 1024,
285 }
286 }
287}
288
289#[derive(Clone, Debug, PartialEq, Eq)]
291pub struct WgpuDiscoveryError {
292 message: String,
293}
294
295impl WgpuDiscoveryError {
296 pub fn new(message: impl Into<String>) -> Self {
298 Self {
299 message: message.into(),
300 }
301 }
302}
303
304impl std::fmt::Display for WgpuDiscoveryError {
305 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 formatter.write_str(&self.message)
307 }
308}
309
310impl std::error::Error for WgpuDiscoveryError {}