nvapi_sys/
nvapi.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2use std::os::raw::c_void;
3use status::{Status, NvAPI_Status};
4use types;
5
6pub type QueryInterfaceFn = extern "C" fn(id: u32) -> *const c_void;
7
8#[cfg(all(windows, target_pointer_width = "32"))]
9pub const LIBRARY_NAME: &'static [u8; 10] = b"nvapi.dll\0";
10#[cfg(all(windows, target_pointer_width = "64"))]
11pub const LIBRARY_NAME: &'static [u8; 12] = b"nvapi64.dll\0";
12
13pub const FN_NAME: &'static [u8; 21] = b"nvapi_QueryInterface\0";
14
15static QUERY_INTERFACE_CACHE: AtomicUsize = AtomicUsize::new(0);
16
17pub unsafe fn set_query_interface(ptr: QueryInterfaceFn) {
18    QUERY_INTERFACE_CACHE.store(ptr as usize, Ordering::Relaxed);
19}
20
21#[cfg(not(windows))]
22pub fn nvapi_QueryInterface(id: u32) -> ::Result<usize> {
23    // TODO: Apparently nvapi is available for macOS?
24    Err(Status::LibraryNotFound)
25}
26
27#[cfg(windows)]
28pub fn nvapi_QueryInterface(id: u32) -> ::Result<usize> {
29    use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA};
30    use std::mem;
31    use std::os::raw::c_char;
32
33    unsafe {
34        let ptr = match QUERY_INTERFACE_CACHE.load(Ordering::Relaxed) {
35            0 => {
36                let lib = LoadLibraryA(LIBRARY_NAME.as_ptr() as *const c_char);
37                if lib.is_null() {
38                    Err(Status::LibraryNotFound)
39                } else {
40                    let ptr = GetProcAddress(lib, FN_NAME.as_ptr() as *const c_char);
41                    if ptr.is_null() {
42                        Err(Status::LibraryNotFound)
43                    } else {
44                        QUERY_INTERFACE_CACHE.store(ptr as usize, Ordering::Relaxed);
45                        Ok(ptr as usize)
46                    }
47                }
48            },
49            ptr => Ok(ptr),
50        }?;
51
52        match mem::transmute::<_, QueryInterfaceFn>(ptr)(id) as usize {
53            0 => Err(Status::NoImplementation),
54            ptr => Ok(ptr),
55        }
56    }
57}
58
59pub(crate) fn query_interface(id: u32, cache: &AtomicUsize) -> ::Result<usize> {
60    match cache.load(Ordering::Relaxed) {
61        0 => {
62            let value = nvapi_QueryInterface(id)?;
63            cache.store(value, Ordering::Relaxed);
64            Ok(value)
65        },
66        value => Ok(value),
67    }
68}
69
70nvapi! {
71    pub type InitializeFn = extern "C" fn() -> NvAPI_Status;
72
73    /// This function initializes the NvAPI library (if not already initialized) but always increments the ref-counter.
74    /// This must be called before calling other NvAPI_ functions.
75    pub unsafe fn NvAPI_Initialize;
76}
77
78nvapi! {
79    pub type UnloadFn = extern "C" fn() -> NvAPI_Status;
80
81    /// Decrements the ref-counter and when it reaches ZERO, unloads NVAPI library.
82    /// This must be called in pairs with NvAPI_Initialize.
83    ///
84    /// Unloading NvAPI library is not supported when the library is in a resource locked state.
85    /// Some functions in the NvAPI library initiates an operation or allocates certain resources
86    /// and there are corresponding functions available, to complete the operation or free the
87    /// allocated resources. All such function pairs are designed to prevent unloading NvAPI library.
88    ///
89    /// For example, if NvAPI_Unload is called after NvAPI_XXX which locks a resource, it fails with
90    /// NVAPI_ERROR. Developers need to call the corresponding NvAPI_YYY to unlock the resources,
91    /// before calling NvAPI_Unload again.
92    ///
93    /// Note: By design, it is not mandatory to call NvAPI_Initialize before calling any NvAPI.
94    /// When any NvAPI is called without first calling NvAPI_Initialize, the internal refcounter
95    /// will be implicitly incremented. In such cases, calling NvAPI_Initialize from a different thread will
96    /// result in incrementing the refcount again and the user has to call NvAPI_Unload twice to
97    /// unload the library. However, note that the implicit increment of the refcounter happens only once.
98    /// If the client wants unload functionality, it is recommended to always call NvAPI_Initialize and NvAPI_Unload in pairs.
99    pub unsafe fn NvAPI_Unload;
100}
101
102nvapi! {
103    pub type GetErrorMessageFn = extern "C" fn(nr: NvAPI_Status, szDesc: *mut types::NvAPI_ShortString) -> NvAPI_Status;
104
105    /// This function converts an NvAPI error code into a null terminated string.
106    pub unsafe fn NvAPI_GetErrorMessage;
107}
108
109nvapi! {
110    pub type GetInterfaceVersionStringFn = extern "C" fn(szDesc: *mut types::NvAPI_ShortString) -> NvAPI_Status;
111
112    /// This function returns a string describing the version of the NvAPI library.
113    /// The contents of the string are human readable.  Do not assume a fixed format.
114    pub unsafe fn NvAPI_GetInterfaceVersionString;
115}
116