Skip to content

Commit dab07d6

Browse files
authored
Include nvml at runtime (#26)
* handle nvml dynamically * make nvmlLib instead of using HMODULE * Update main.cpp * remove CUDA from CI * uhhhhh lol
1 parent e74810f commit dab07d6

File tree

4 files changed

+111
-47
lines changed

4 files changed

+111
-47
lines changed

.github/workflows/vs17.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ jobs:
1010
with:
1111
submodules: true
1212
fetch-depth: 0
13-
- uses: Jimver/cuda-toolkit@v0.2.10
14-
id: cuda-toolkit
15-
with:
16-
cuda: '12.1.0'
1713
- name: Configure
1814
run: cmake -B build
1915
- name: Build Debug

CMakeLists.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.15)
1+
cmake_minimum_required(VERSION 3.17)
22

33
project(OpenVR-Dynamic-Resolution)
44

@@ -25,11 +25,10 @@ include_directories(include)
2525
set(CMAKE_SKIP_BUILD_RPATH FALSE)
2626
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
2727
set(CMAKE_INSTALL_RPATH $ORIGIN)
28-
include_directories("C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v12.1/include")
2928

3029
# Project
3130
add_executable("${PROJECT_NAME}" "src/main.cpp" "src/pathtools_excerpt.cpp" "src/setup.cpp")
32-
target_link_libraries("${PROJECT_NAME}" PRIVATE "${OPENVR_LIB}" fmt::fmt-header-only ${CURSES_LIBRARIES} "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v12.1/lib/x64/nvml.lib")
31+
target_link_libraries("${PROJECT_NAME}" PRIVATE "${OPENVR_LIB}" fmt::fmt-header-only ${CURSES_LIBRARIES})
3332
target_include_directories("${PROJECT_NAME}" PUBLIC ${protos_OUTPUT_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
3433
target_compile_features("${PROJECT_NAME}" PRIVATE cxx_std_17)
3534

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ Settings are found in the `settings.ini` file. Do not rename that file. It shoul
6161

6262
## Building from source
6363

64-
We assume that you already have Git, Cuda and CMake installed.
65-
Depending on where you installed cuda, you may need to edit the include and lib paths in the CMakeLists.txt file.
66-
It is assumed that you have cuda 12.1, however, older versions may work if the path is specified.
64+
We assume that you already have Git and CMake installed.
6765
To build the project, run:
6866

6967
```

src/main.cpp

Lines changed: 108 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
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"
@@ -15,7 +17,7 @@
1517
using namespace std::chrono_literals;
1618
using namespace vr;
1719

18-
static constexpr const char *version = "v.0.3.1";
20+
static constexpr const char *version = "v.0.3.2";
1921

2022
int autoStart = 1;
2123
int minimizeOnStart = 0;
@@ -39,33 +41,59 @@ float vramTarget = 0.8;
3941
float vramLimit = 0.9;
4042
int 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

7199
bool loadSettings()
@@ -110,6 +138,12 @@ long getCurrentTimeMillis()
110138

111139
int 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

Comments
 (0)