Skip to main content

singe_nvml/
vgpu_instance.rs

1#[allow(unused_imports)]
2use crate::error::Status;
3
4use singe_core::string_from_c_chars;
5use singe_nvml_sys as sys;
6use std::{mem, ptr};
7
8use crate::{
9    error::Result,
10    try_ffi,
11    types::{
12        AccountingStats, EnableState, EncoderSessionInfo, EncoderStats, FbcSessionInfo, FbcStats,
13        Pid, VgpuCompatibility, VgpuInstanceId, VgpuLicenseInfo, VgpuMetadata, VgpuPlacementId,
14        VgpuRuntimeState, VgpuTypeId, VgpuVmId, VgpuVmIdType,
15    },
16    utility::{query_sized_raw, query_u32_list, struct_version},
17};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20#[repr(transparent)]
21pub struct VgpuInstance(sys::nvmlVgpuInstance_t);
22
23impl VgpuInstance {
24    pub const fn from_id(id: VgpuInstanceId) -> Self {
25        Self(id.0)
26    }
27
28    pub const fn id(self) -> VgpuInstanceId {
29        VgpuInstanceId(self.0)
30    }
31
32    /// Returns the vGPU type of a vGPU instance.
33    ///
34    /// Returns the vGPU type ID assigned to the vGPU instance.
35    ///
36    /// For Kepler or newer fully supported devices.
37    ///
38    /// # Errors
39    ///
40    /// Returns an error if NVML rejects the handle or output argument, if the
41    /// handle does not match an active vGPU instance, if NVML has not been
42    /// initialized, or if NVML reports an unexpected failure.
43    pub fn vgpu_type(self) -> Result<VgpuTypeId> {
44        let mut vgpu_type_id = 0;
45        unsafe {
46            try_ffi!(sys::nvmlVgpuInstanceGetType(self.0, &raw mut vgpu_type_id))?;
47        }
48        Ok(VgpuTypeId(vgpu_type_id))
49    }
50
51    /// Query the placement ID of active vGPU instance.
52    ///
53    /// When vGPU heterogeneous mode is enabled, returns the placement ID for the vGPU instance.
54    ///
55    /// # Errors
56    ///
57    /// Returns an error if NVML rejects the versioned request, if the vGPU
58    /// instance or query arguments are invalid, if the handle does not match an
59    /// active vGPU instance, or if NVML reports an unexpected failure.
60    pub fn placement_id(self) -> Result<VgpuPlacementId> {
61        let mut placement = sys::nvmlVgpuPlacementId_t {
62            version: struct_version::<sys::nvmlVgpuPlacementId_t>(1),
63            ..Default::default()
64        };
65        unsafe {
66            try_ffi!(sys::nvmlVgpuInstanceGetPlacementId(
67                self.0,
68                &raw mut placement
69            ))?;
70        }
71        Ok(placement.into())
72    }
73
74    /// Queries the state of per process accounting mode on vGPU.
75    ///
76    /// For Maxwell or newer fully supported devices.
77    ///
78    /// # Errors
79    ///
80    /// Returns an error if the guest driver is not running, if NVML rejects
81    /// the handle or output argument, if the handle does not match an active
82    /// vGPU instance, if the vGPU does not support accounting, if NVML has not
83    /// been initialized, or if NVML reports an unexpected failure.
84    pub fn accounting_mode(self) -> Result<EnableState> {
85        let mut mode = sys::nvmlEnableState_t::NVML_FEATURE_DISABLED;
86        unsafe {
87            try_ffi!(sys::nvmlVgpuInstanceGetAccountingMode(
88                self.0,
89                &raw mut mode
90            ))?;
91        }
92        Ok(mode.into())
93    }
94
95    /// Returns processes running on this vGPU instance that have accounting stats.
96    /// Returned processes can be running or terminated.
97    ///
98    /// For Maxwell or newer fully supported devices.
99    ///
100    /// This wrapper queries the required process count internally.
101    /// It returns an empty list when no processes are available.
102    ///
103    /// See [`VgpuInstance::accounting_stats`] for the per-process metrics.
104    ///
105    /// With a PID collision, some processes may not be accessible before the circular buffer is full.
106    ///
107    /// # Errors
108    ///
109    /// Returns an error if the internal PID buffer is too small, if NVML
110    /// rejects the handle or process-count output, if the handle does not match
111    /// an active vGPU instance, if the vGPU does not support accounting or
112    /// accounting is disabled, if NVML has not been initialized, or if NVML
113    /// reports an unexpected failure.
114    pub fn accounting_pids(self) -> Result<Vec<Pid>> {
115        Ok(query_u32_list(|count, values| unsafe {
116            sys::nvmlVgpuInstanceGetAccountingPids(self.0, count, values)
117        })?
118        .into_iter()
119        .map(Pid)
120        .collect())
121    }
122
123    /// Queries process's accounting stats.
124    ///
125    /// For Maxwell or newer fully supported devices.
126    ///
127    /// Accounting stats capture GPU utilization and other statistics across the lifetime of a process.
128    /// Stats can be queried while the process is running and after it terminates.
129    /// The reported running time remains 0 while the process is still running and is updated to the actual duration after termination.
130    /// Accounting stats are kept in a circular buffer, newly created processes overwrite information about old processes.
131    ///
132    /// The returned value includes the per-process accounting metrics exposed by NVML.
133    /// Use [`VgpuInstance::accounting_pids`] to list processes with available stats.
134    ///
135    /// * Accounting mode must be enabled.
136    ///   See [`VgpuInstance::accounting_mode`].
137    /// * Only compute and graphics application stats can be queried.
138    ///   Monitoring application stats cannot be queried because they do not contribute to GPU utilization.
139    /// * With a PID collision, only stats for the latest process to terminate are reported.
140    ///
141    /// # Errors
142    ///
143    /// Returns an error if NVML rejects the handle or stats output, if the
144    /// handle does not match an active vGPU instance or stats are unavailable,
145    /// if the vGPU does not support accounting or accounting is disabled, if
146    /// NVML has not been initialized, or if NVML reports an unexpected failure.
147    pub fn accounting_stats(self, pid: Pid) -> Result<AccountingStats> {
148        let mut stats = sys::nvmlAccountingStats_t::default();
149        unsafe {
150            try_ffi!(sys::nvmlVgpuInstanceGetAccountingStats(
151                self.0,
152                pid.0,
153                &raw mut stats,
154            ))?;
155        }
156        Ok(stats.into())
157    }
158
159    /// Returns the UUID of a vGPU instance.
160    ///
161    /// The UUID is a globally unique identifier associated with the vGPU.
162    /// It is returned as a five-part hexadecimal string that does not exceed 80
163    /// characters including the terminating NUL byte.
164    /// This wrapper allocates the required NVML buffer internally.
165    ///
166    /// For Kepler or newer fully supported devices.
167    ///
168    /// # Errors
169    ///
170    /// Returns an error if the UUID buffer is too small, if NVML rejects the
171    /// handle or output argument, if the handle does not match an active vGPU
172    /// instance, if NVML has not been initialized, or if NVML reports an
173    /// unexpected failure.
174    pub fn uuid(self) -> Result<String> {
175        let mut buffer = [0i8; sys::NVML_DEVICE_UUID_BUFFER_SIZE as usize];
176        unsafe {
177            try_ffi!(sys::nvmlVgpuInstanceGetUUID(
178                self.0,
179                buffer.as_mut_ptr(),
180                buffer.len() as u32,
181            ))?;
182        }
183        Ok(string_from_c_chars(&buffer))
184    }
185
186    /// Returns the VM ID associated with a vGPU instance.
187    ///
188    /// The VM ID is returned as a string that does not exceed 80 characters
189    /// including the terminating NUL byte.
190    /// This wrapper allocates the required NVML buffer internally.
191    ///
192    /// The VM ID type identifies the platform-specific format of the returned string.
193    ///
194    /// For Kepler or newer fully supported devices.
195    ///
196    /// # Errors
197    ///
198    /// Returns an error if the VM ID buffer is too small, if NVML rejects the
199    /// handle, VM ID, or VM ID type output, if the handle does not match an
200    /// active vGPU instance, if NVML has not been initialized, or if NVML
201    /// reports an unexpected failure.
202    pub fn vm_id(self) -> Result<VgpuVmId> {
203        let mut buffer = [0i8; sys::NVML_DEVICE_UUID_BUFFER_SIZE as usize];
204        let mut vm_id_type = sys::nvmlVgpuVmIdType_t::NVML_VGPU_VM_ID_DOMAIN_ID;
205        unsafe {
206            try_ffi!(sys::nvmlVgpuInstanceGetVmID(
207                self.0,
208                buffer.as_mut_ptr(),
209                buffer.len() as u32,
210                &raw mut vm_id_type,
211            ))?;
212        }
213        Ok(VgpuVmId {
214            value: string_from_c_chars(&buffer),
215            kind: VgpuVmIdType::from(vm_id_type),
216        })
217    }
218
219    /// Returns the NVIDIA driver version installed in the VM associated with a vGPU.
220    ///
221    /// The version is returned as an alphanumeric string.
222    /// The version string does not exceed 80 bytes including the terminating
223    /// NUL byte.
224    /// This wrapper allocates the required NVML buffer internally.
225    ///
226    /// [`VgpuInstance::vm_driver_version`] may be called at any time for a vGPU instance.
227    /// The guest VM driver version is returned as `Not Available` if no NVIDIA
228    /// driver is installed in the VM, or if the VM has not yet loaded and
229    /// initialized the NVIDIA driver.
230    ///
231    /// For Kepler or newer fully supported devices.
232    ///
233    /// # Errors
234    ///
235    /// Returns an error if the internal driver-version buffer is too small, if
236    /// NVML rejects the handle, if the handle does not match an active vGPU
237    /// instance, if NVML has not been initialized, or if NVML reports an
238    /// unexpected failure.
239    pub fn vm_driver_version(self) -> Result<String> {
240        let mut buffer = [0i8; sys::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE as usize];
241        unsafe {
242            try_ffi!(sys::nvmlVgpuInstanceGetVmDriverVersion(
243                self.0,
244                buffer.as_mut_ptr(),
245                buffer.len() as u32,
246            ))?;
247        }
248        Ok(string_from_c_chars(&buffer))
249    }
250
251    /// Returns the MDEV UUID of a vGPU instance.
252    ///
253    /// The MDEV UUID is a globally unique identifier of the mdev device assigned
254    /// to the VM.
255    /// It is returned as a five-part hexadecimal string that does not exceed 80
256    /// characters including the terminating NUL byte.
257    /// The MDEV UUID is displayed only on KVM.
258    /// This wrapper allocates the required NVML buffer internally.
259    ///
260    /// For Maxwell or newer fully supported devices.
261    ///
262    /// # Errors
263    ///
264    /// Returns an error if the mediated-device UUID buffer is too small, if
265    /// NVML rejects the handle or UUID output, if the handle does not match an
266    /// active vGPU instance, if the hypervisor is not KVM, if NVML has not been
267    /// initialized, or if NVML reports an unexpected failure.
268    pub fn mdev_uuid(self) -> Result<String> {
269        let mut buffer = [0i8; sys::NVML_DEVICE_UUID_BUFFER_SIZE as usize];
270        unsafe {
271            try_ffi!(sys::nvmlVgpuInstanceGetMdevUUID(
272                self.0,
273                buffer.as_mut_ptr(),
274                buffer.len() as u32,
275            ))?;
276        }
277        Ok(string_from_c_chars(&buffer))
278    }
279
280    /// Returns the framebuffer usage in bytes.
281    ///
282    /// Framebuffer usage is the amount of vGPU framebuffer memory that is currently in use by the VM.
283    ///
284    /// For Kepler or newer fully supported devices.
285    ///
286    /// # Errors
287    ///
288    /// Returns an error if NVML rejects the handle or output argument, if the
289    /// handle does not match an active vGPU instance, if NVML has not been
290    /// initialized, or if NVML reports an unexpected failure.
291    pub fn framebuffer_usage(self) -> Result<u64> {
292        let mut usage = 0;
293        unsafe {
294            try_ffi!(sys::nvmlVgpuInstanceGetFbUsage(self.0, &raw mut usage))?;
295        }
296        Ok(usage)
297    }
298
299    pub fn license_status(self) -> Result<bool> {
300        Ok(self.license_info()?.is_licensed)
301    }
302
303    /// Query the license information of the vGPU instance.
304    ///
305    /// For Maxwell or newer fully supported devices.
306    ///
307    /// # Errors
308    ///
309    /// Returns an error if the guest driver is not running, if NVML rejects
310    /// the handle or output argument, if the handle does not match an active
311    /// vGPU instance, or if NVML reports an unexpected failure.
312    pub fn license_info(self) -> Result<VgpuLicenseInfo> {
313        let mut info = sys::nvmlVgpuLicenseInfo_t::default();
314        unsafe {
315            try_ffi!(sys::nvmlVgpuInstanceGetLicenseInfo_v2(
316                self.0,
317                &raw mut info
318            ))?;
319        }
320        Ok(info.into())
321    }
322
323    /// Returns the frame rate limit set for the vGPU instance.
324    ///
325    /// Returns the value of the frame-rate limit set for the vGPU instance.
326    ///
327    /// For Kepler or newer fully supported devices.
328    ///
329    /// # Errors
330    ///
331    /// Returns an error if NVML rejects the handle or output argument, if the
332    /// handle does not match an active vGPU instance, if the frame-rate limiter
333    /// is disabled for this vGPU type, if NVML has not been initialized, or if
334    /// NVML reports an unexpected failure.
335    pub fn frame_rate_limit(self) -> Result<u32> {
336        let mut limit = 0;
337        unsafe {
338            try_ffi!(sys::nvmlVgpuInstanceGetFrameRateLimit(
339                self.0,
340                &raw mut limit
341            ))?;
342        }
343        Ok(limit)
344    }
345
346    /// Returns the current ECC mode of a vGPU instance.
347    ///
348    /// # Errors
349    ///
350    /// Returns an error if NVML rejects the handle or output argument, if the
351    /// handle does not match an active vGPU instance, if the vGPU does not
352    /// support ECC mode, if NVML has not been initialized, or if NVML reports an
353    /// unexpected failure.
354    pub fn ecc_mode(self) -> Result<EnableState> {
355        let mut mode = sys::nvmlEnableState_t::NVML_FEATURE_DISABLED;
356        unsafe {
357            try_ffi!(sys::nvmlVgpuInstanceGetEccMode(self.0, &raw mut mode))?;
358        }
359        Ok(mode.into())
360    }
361
362    /// Returns the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100.
363    ///
364    /// For Maxwell or newer fully supported devices.
365    ///
366    /// # Errors
367    ///
368    /// Returns an error if NVML rejects the handle or encoder query, if the
369    /// handle does not match an active vGPU instance, if NVML has not been
370    /// initialized, or if NVML reports an unexpected failure.
371    pub fn encoder_capacity(self) -> Result<u32> {
372        let mut capacity = 0;
373        unsafe {
374            try_ffi!(sys::nvmlVgpuInstanceGetEncoderCapacity(
375                self.0,
376                &raw mut capacity
377            ))?;
378        }
379        Ok(capacity)
380    }
381
382    /// Returns the current encoder statistics of a vGPU instance.
383    ///
384    /// For Maxwell or newer fully supported devices.
385    ///
386    /// # Errors
387    ///
388    /// Returns an error if NVML rejects the handle or query arguments, if the
389    /// handle does not match an active vGPU instance, if NVML has not been
390    /// initialized, or if NVML reports an unexpected failure.
391    pub fn encoder_stats(self) -> Result<EncoderStats> {
392        let mut session_count = 0;
393        let mut average_fps = 0;
394        let mut average_latency_us = 0;
395        unsafe {
396            try_ffi!(sys::nvmlVgpuInstanceGetEncoderStats(
397                self.0,
398                &raw mut session_count,
399                &raw mut average_fps,
400                &raw mut average_latency_us,
401            ))?;
402        }
403        Ok(EncoderStats {
404            session_count,
405            average_fps,
406            average_latency_us,
407        })
408    }
409
410    /// Returns information about all active encoder sessions on a vGPU instance.
411    ///
412    /// This wrapper queries the required session count first, then returns the active encoder sessions as a [`Vec`].
413    ///
414    /// For Maxwell or newer fully supported devices.
415    ///
416    /// # Errors
417    ///
418    /// Returns an error if the internal session buffer is too small, if NVML
419    /// rejects the handle or reports an invalid session count, if the handle
420    /// does not match an active vGPU instance, if NVML has not been
421    /// initialized, or if NVML reports an unexpected failure.
422    pub fn encoder_sessions(self) -> Result<Vec<EncoderSessionInfo>> {
423        let mut count = 0;
424        let status = unsafe {
425            sys::nvmlVgpuInstanceGetEncoderSessions(self.0, &raw mut count, ptr::null_mut())
426        };
427        if status == sys::nvmlReturn_t::NVML_SUCCESS && count == 0 {
428            return Ok(Vec::new());
429        }
430        if status != sys::nvmlReturn_t::NVML_ERROR_INSUFFICIENT_SIZE {
431            return Err(status.into());
432        }
433
434        let mut sessions = vec![sys::nvmlEncoderSessionInfo_t::default(); count as usize];
435        unsafe {
436            try_ffi!(sys::nvmlVgpuInstanceGetEncoderSessions(
437                self.0,
438                &raw mut count,
439                sessions.as_mut_ptr(),
440            ))?;
441        }
442        sessions.truncate(count as usize);
443        Ok(sessions.into_iter().map(Into::into).collect())
444    }
445
446    /// Returns the active frame buffer capture sessions statistics of a vGPU instance.
447    ///
448    /// For Maxwell or newer fully supported devices.
449    ///
450    /// # Errors
451    ///
452    /// Returns an error if NVML rejects the handle or output argument, if the
453    /// handle does not match an active vGPU instance, if NVML has not been
454    /// initialized, or if NVML reports an unexpected failure.
455    pub fn fbc_stats(self) -> Result<FbcStats> {
456        let mut stats = sys::nvmlFBCStats_t::default();
457        unsafe {
458            try_ffi!(sys::nvmlVgpuInstanceGetFBCStats(self.0, &raw mut stats))?;
459        }
460        Ok(stats.into())
461    }
462
463    /// Returns information about active frame buffer capture sessions on a vGPU instance.
464    ///
465    /// This wrapper queries the required session count first, then returns the active FBC sessions as a [`Vec`].
466    ///
467    /// For Maxwell or newer fully supported devices.
468    ///
469    /// `h_resolution`, `v_resolution`, `average_fps`, and `average_latency` may be zero if no new frames were captured since the session started.
470    ///
471    /// # Errors
472    ///
473    /// Returns an error if the internal session buffer is too small, if NVML
474    /// rejects the handle or reports an invalid session count, if the handle
475    /// does not match an active vGPU instance, if NVML has not been
476    /// initialized, or if NVML reports an unexpected failure.
477    pub fn fbc_sessions(self) -> Result<Vec<FbcSessionInfo>> {
478        let mut count = 0;
479        let status =
480            unsafe { sys::nvmlVgpuInstanceGetFBCSessions(self.0, &raw mut count, ptr::null_mut()) };
481        if status == sys::nvmlReturn_t::NVML_SUCCESS && count == 0 {
482            return Ok(Vec::new());
483        }
484        if status != sys::nvmlReturn_t::NVML_ERROR_INSUFFICIENT_SIZE {
485            return Err(status.into());
486        }
487
488        let mut sessions = vec![sys::nvmlFBCSessionInfo_t::default(); count as usize];
489        unsafe {
490            try_ffi!(sys::nvmlVgpuInstanceGetFBCSessions(
491                self.0,
492                &raw mut count,
493                sessions.as_mut_ptr(),
494            ))?;
495        }
496        sessions.truncate(count as usize);
497        Ok(sessions.into_iter().map(Into::into).collect())
498    }
499
500    /// Returns the GPU instance ID for the given vGPU instance.
501    /// Returns a valid GPU instance ID for MIG-backed vGPU instances; otherwise returns `INVALID_GPU_INSTANCE_ID`.
502    ///
503    /// For Kepler or newer fully supported devices.
504    ///
505    /// # Errors
506    ///
507    /// Returns an error if NVML rejects the handle or query arguments, if the
508    /// handle does not match an active vGPU instance, if NVML has not been
509    /// initialized, or if NVML reports an unexpected failure.
510    pub fn gpu_instance_id(self) -> Result<u32> {
511        let mut id = 0;
512        unsafe {
513            try_ffi!(sys::nvmlVgpuInstanceGetGpuInstanceId(self.0, &raw mut id))?;
514        }
515        Ok(id)
516    }
517
518    /// Returns the PCI ID of the given vGPU instance, that is, the PCI ID of the GPU as seen inside the VM.
519    ///
520    /// The vGPU PCI ID is returned as `00000000:00:00.0` if the NVIDIA driver is
521    /// not installed on the vGPU instance.
522    ///
523    /// # Errors
524    ///
525    /// Returns an error if the guest driver is not running, if the internal PCI
526    /// ID buffer is too small, if NVML rejects the handle or output argument, if
527    /// the handle does not match an active vGPU instance, if NVML has not been
528    /// initialized, or if NVML reports an unexpected failure.
529    pub fn gpu_pci_id(self) -> Result<String> {
530        let mut buffer = [0i8; sys::NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE as usize];
531        let mut length = buffer.len() as u32;
532        unsafe {
533            try_ffi!(sys::nvmlVgpuInstanceGetGpuPciId(
534                self.0,
535                buffer.as_mut_ptr(),
536                &raw mut length,
537            ))?;
538        }
539        Ok(string_from_c_chars(&buffer))
540    }
541
542    /// Returns the currently used runtime state size of the vGPU instance.
543    ///
544    /// This size represents the maximum in-memory data size used by a vGPU instance during standard operation.
545    /// This measurement is exclusive of frame buffer (FB) data size assigned to the vGPU instance.
546    ///
547    /// For Maxwell or newer fully supported devices.
548    ///
549    /// # Errors
550    ///
551    /// Returns an error if NVML rejects the versioned request, if the vGPU
552    /// instance or query arguments are invalid, if the handle does not match an
553    /// active vGPU instance, if NVML has not been initialized, or if NVML
554    /// reports an unexpected failure.
555    pub fn runtime_state(self) -> Result<VgpuRuntimeState> {
556        let mut state = sys::nvmlVgpuRuntimeState_t {
557            version: struct_version::<sys::nvmlVgpuRuntimeState_t>(1),
558            ..Default::default()
559        };
560        unsafe {
561            try_ffi!(sys::nvmlVgpuInstanceGetRuntimeStateSize(
562                self.0,
563                &raw mut state
564            ))?;
565        }
566        Ok(state.into())
567    }
568
569    /// Returns vGPU metadata structure for a running vGPU.
570    /// The structure contains information about the vGPU and its associated VM such as the currently installed NVIDIA guest driver version, together with host driver version and an opaque data section containing internal state.
571    ///
572    /// [`VgpuInstance::metadata`] may be called at any time for a vGPU instance.
573    /// Some fields in the returned structure are dependent on information obtained from the guest VM, which may not yet have reached a state where that information is available.
574    /// The current state of these dependent fields is reflected in the info structure's [`VgpuGuestInfoState`](crate::types::VgpuGuestInfoState) field.
575    ///
576    /// The VMM may choose to read and save the vGPU's VM info as persistent metadata associated with the VM, and provide it to Virtual GPU Manager when creating a vGPU for subsequent instances of the VM.
577    ///
578    /// This wrapper allocates the metadata buffer internally and retries if NVML reports it is too small.
579    ///
580    /// # Errors
581    ///
582    /// Returns an error if the internal metadata buffer is too small after
583    /// retrying, if NVML rejects the handle or metadata arguments, if the handle
584    /// does not match an active vGPU instance, or if NVML reports an unexpected
585    /// failure.
586    pub fn metadata(self) -> Result<VgpuMetadata> {
587        let raw = query_sized_raw(|size, buffer| unsafe {
588            sys::nvmlVgpuInstanceGetMetadata(self.0, buffer.cast(), size)
589        })?;
590
591        let metadata = unsafe { &*raw.as_ptr().cast::<sys::nvmlVgpuMetadata_t>() };
592        let opaque_offset = mem::offset_of!(sys::nvmlVgpuMetadata_t, opaqueData);
593        let opaque_end = opaque_offset.saturating_add(metadata.opaqueDataSize as usize);
594        let opaque_data = raw[opaque_offset..opaque_end].to_vec();
595
596        Ok(VgpuMetadata::from_raw(metadata, opaque_data))
597    }
598
599    pub fn compatibility_with(
600        self,
601        library: &crate::library::Library,
602        pgpu_metadata: &crate::types::PgpuMetadata,
603    ) -> Result<VgpuCompatibility> {
604        let vgpu_metadata = self.metadata()?;
605        library.vgpu_compatibility(&vgpu_metadata, pgpu_metadata)
606    }
607}