55#include < args.hxx>
66#include < curses.h>
77#include < stdlib.h>
8- #if __has_include("nvml.h")
9- #include < nvml.h>
8+ #ifdef _WIN32
9+ #include < Windows.h>
10+ #else
11+ #include < dlfcn.h>
1012#endif
1113
1214#include " SimpleIni.h"
1517using namespace std ::chrono_literals;
1618using namespace vr ;
1719
18- static constexpr const char *version = " v.0.3.1 " ;
20+ static constexpr const char *version = " v.0.3.2 " ;
1921
2022int autoStart = 1 ;
2123int minimizeOnStart = 0 ;
@@ -39,33 +41,59 @@ float vramTarget = 0.8;
3941float vramLimit = 0.9 ;
4042int vramMonitorEnabled = 1 ;
4143
42- #if __has_include("nvml.h")
43- nvmlDevice_t nvmlDevice;
44+ // NVML stuff
45+ typedef enum nvmlReturn_enum
46+ {
47+ NVML_SUCCESS = 0 , // The operation was successful.
48+ NVML_ERROR_UNINITIALIZED = 1 , // NVML was not first initialized with nvmlInit().
49+ NVML_ERROR_INVALID_ARGUMENT = 2 , // A supplied argument is invalid.
50+ NVML_ERROR_NOT_SUPPORTED = 3 , // The requested operation is not available on target device.
51+ NVML_ERROR_NO_PERMISSION = 4 , // The currrent user does not have permission for operation.
52+ NVML_ERROR_ALREADY_INITIALIZED = 5 , // NVML has already been initialized.
53+ NVML_ERROR_NOT_FOUND = 6 , // A query to find an object was unccessful.
54+ NVML_ERROR_UNKNOWN = 7 , // An internal driver error occurred.
55+ } nvmlReturn_t;
56+ typedef nvmlReturn_t (*nvmlInit_t)();
57+ typedef nvmlReturn_t (*nvmlShutdown_t)();
58+ typedef struct
59+ {
60+ unsigned long long total;
61+ unsigned long long free;
62+ unsigned long long used;
63+ } nvmlMemory_t;
64+ typedef nvmlReturn_t (*nvmlDevice_t)();
65+ typedef nvmlReturn_t (*nvmlDeviceGetHandleByIndex_t)(unsigned int , nvmlDevice_t *);
66+ typedef nvmlReturn_t (*nvmlDeviceGetMemoryInfo_t)(nvmlDevice_t, nvmlMemory_t *);
67+ #ifdef _WIN32
68+ typedef HMODULE (nvmlLib);
69+ #else
70+ typedef void *(nvmlLib);
4471#endif
4572
46- float getVramUsage ()
73+ nvmlDevice_t nvmlDevice;
74+
75+ float getVramUsage (nvmlLib nvmlLibrary)
4776{
48- if (vramMonitorEnabled == 0 )
49- {
77+ if (vramMonitorEnabled == 0 || !nvmlLibrary)
5078 return 0 .0f ;
51- }
52- #if __has_include("nvml.h")
79+
5380 nvmlReturn_t result;
54- nvmlMemory_t memory ;
81+ nvmlMemory_t memoryInfo ;
5582 unsigned int deviceCount;
5683
5784 // Get memory info
58- result = nvmlDeviceGetMemoryInfo (nvmlDevice, &memory);
85+ nvmlDeviceGetMemoryInfo_t nvmlDeviceGetMemoryInfoPtr;
86+ #ifdef _WIN32
87+ nvmlDeviceGetMemoryInfoPtr = (nvmlDeviceGetMemoryInfo_t)GetProcAddress (nvmlLibrary, " nvmlDeviceGetMemoryInfo" );
88+ #else
89+ nvmlDeviceGetMemoryInfoPtr = (nvmlDeviceGetMemoryInfo_t)dlsym (nvmlLibrary, " nvmlDeviceGetMemoryInfo" );
90+ #endif
91+ result = nvmlDeviceGetMemoryInfoPtr (nvmlDevice, &memoryInfo);
5992 if (result != NVML_SUCCESS)
60- {
61- return -1 .0f ;
62- }
93+ return -result;
6394
6495 // Return VRAM usage as a percentage
65- return (float )memory.used / (float )memory.total ;
66- #endif
67-
68- return 0 .0f ;
96+ return (float )memoryInfo.used / (float )memoryInfo.total ;
6997}
7098
7199bool loadSettings ()
@@ -110,6 +138,12 @@ long getCurrentTimeMillis()
110138
111139int main (int argc, char *argv[])
112140{
141+ #ifdef _WIN32
142+ HMODULE nvmlLibrary = LoadLibraryA (" nvml.dll" );
143+ #else
144+ void *nvmlLibrary = dlopen (" libnvidia-ml.so" , RTLD_LAZY);
145+ #endif
146+
113147 int rows, cols; // max rows and cols
114148 initscr (); // Initialize screen
115149 cbreak (); // Disable line-buffering (for input)
@@ -147,11 +181,6 @@ int main(int argc, char *argv[])
147181 ShowWindow (GetConsoleWindow (), SW_HIDE);
148182#endif
149183
150- #if defined(__linux__)
151- // VRAM monitoring is not supported on Linux
152- vramMonitorEnabled = false ;
153- #endif
154-
155184 // Set auto-start
156185 int autoStartResult = handle_setup (autoStart);
157186
@@ -175,27 +204,49 @@ int main(int argc, char *argv[])
175204 vr::VRSettings ()->SetFloat (vr::k_pch_SteamVR_Section,
176205 vr::k_pch_SteamVR_SupersampleScale_Float, initialRes);
177206
178- // Initialise VRAM monitoring stuff
179- #if __has_include("nvml.h")
207+ // Initialise NVML
208+ nvmlInit_t nvmlInitPtr;
209+ #ifdef _WIN32
210+ nvmlInitPtr = (nvmlInit_t)GetProcAddress (nvmlLibrary, " nvmlInit" );
211+ #else
212+ nvmlInitPtr = (nvmlInit_t)dlsym (nvmlLibrary, " nvmlShutdown" );
213+ #endif
214+ if (!nvmlInitPtr)
215+ vramMonitorEnabled = 0 ;
180216 if (vramMonitorEnabled == 1 )
181217 {
182218 nvmlReturn_t result;
183219 // Initialize NVML library
184- result = nvmlInit ();
185- if (NVML_SUCCESS != result)
186- {
220+ result = nvmlInitPtr ();
221+ if (result != NVML_SUCCESS)
187222 vramMonitorEnabled = 0 ;
188- }
189223
190224 // Get device handle
191- result = nvmlDeviceGetHandleByIndex (0 , &nvmlDevice);
192- if (NVML_SUCCESS != result)
225+ nvmlDeviceGetHandleByIndex_t nvmlDeviceGetHandleByIndexPtr;
226+ #ifdef _WIN32
227+ nvmlDeviceGetHandleByIndexPtr = (nvmlDeviceGetHandleByIndex_t)GetProcAddress (nvmlLibrary, " nvmlDeviceGetHandleByIndex" );
228+ #else
229+ nvmlDeviceGetHandleByIndexPtr = (nvmlDeviceGetHandleByIndex_t)dlsym (nvmlLibrary, " nvmlDeviceGetHandleByIndex" );
230+ #endif
231+ if (!nvmlDeviceGetHandleByIndexPtr)
232+ vramMonitorEnabled = 0 ;
233+ else
234+ result = nvmlDeviceGetHandleByIndexPtr (0 , &nvmlDevice);
235+ if (result != NVML_SUCCESS || vramMonitorEnabled == 0 )
193236 {
194- nvmlShutdown ();
237+ nvmlShutdown_t nvmlShutdownPtr;
238+ #ifdef _WIN32
239+ nvmlShutdownPtr = (nvmlShutdown_t)GetProcAddress (nvmlLibrary, " nvmlShutdown" );
240+ #else
241+ nvmlShutdownPtr = (nvmlShutdown_t)dlsym (nvmlLibrary, " nvmlShutdown" );
242+ #endif
195243 vramMonitorEnabled = 0 ;
244+ if (nvmlShutdownPtr)
245+ {
246+ nvmlShutdownPtr ();
247+ }
196248 }
197249 }
198- #endif
199250
200251 // Initialize loop variables
201252 long lastChangeTime = getCurrentTimeMillis ();
@@ -279,7 +330,7 @@ int main(int argc, char *argv[])
279330 mvprintw (9 , 0 , " %s" , fmt::format (" GPU frametime: {} ms" , displayedAverageTime).c_str ());
280331 if (vramMonitorEnabled)
281332 {
282- std::string vramUsage = std::to_string (getVramUsage () * 100 ).substr (0 , 4 );
333+ std::string vramUsage = std::to_string (getVramUsage (nvmlLibrary ) * 100 ).substr (0 , 4 );
283334 mvprintw (10 , 0 , " %s" , fmt::format (" VRAM usage: {}%" , vramUsage).c_str ());
284335 }
285336 else
@@ -315,8 +366,8 @@ int main(int argc, char *argv[])
315366 if (currentTime - resChangeDelayMs > lastChangeTime)
316367 {
317368 lastChangeTime = currentTime;
318- bool vramLimitReached = vramLimit < getVramUsage ();
319- bool vramTargetReached = vramTarget < getVramUsage ();
369+ bool vramLimitReached = vramLimit < getVramUsage (nvmlLibrary );
370+ bool vramTargetReached = vramTarget < getVramUsage (nvmlLibrary );
320371 bool dashboardOpen = VROverlay ()->IsDashboardVisible ();
321372
322373 if (averageGpuTime > minGpuTimeThreshold && !dashboardOpen)
@@ -386,4 +437,24 @@ int main(int argc, char *argv[])
386437 // ZZzzzz
387438 std::this_thread::sleep_for (std::chrono::milliseconds (sleepTime));
388439 }
440+
441+ // TODO actually be able to get out of the while loop
442+
443+ #ifdef _WIN32
444+ nvmlShutdown_t nvmlShutdownPtr = (nvmlShutdown_t)GetProcAddress (nvmlLibrary, " nvmlShutdown" );
445+ if (nvmlShutdownPtr)
446+ {
447+ nvmlShutdownPtr ();
448+ }
449+ FreeLibrary (nvmlLibrary);
450+ #else
451+ nvmlShutdown_t nvmlShutdownPtr = (nvmlShutdown_t)dlsym (nvmlLibrary, " nvmlShutdown" );
452+ if (nvmlShutdownPtr)
453+ {
454+ nvmlShutdownPtr ();
455+ }
456+ dlclose (nvmlLibrary);
457+ #endif
458+
459+ return 0 ;
389460}
0 commit comments