diff --git a/src/gpu.cpp b/src/gpu.cpp index 3faaf602..191ae67a 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -7,18 +7,22 @@ FILE *amdGpuFile = nullptr, *amdTempFile = nullptr, *amdGpuVramTotalFile = nullp pthread_t cpuThread, gpuThread, cpuInfoThread; void *getNvidiaGpuInfo(void *){ - if (!nvmlSuccess) - checkNvidia(); - if (nvmlSuccess){ - getNvidiaInfo(); + getNVMLInfo(); gpu_info.load = nvidiaUtilization.gpu; gpu_info.temp = nvidiaTemp; gpu_info.memoryUsed = nvidiaMemory.used / (1024.f * 1024.f * 1024.f); gpu_info.CoreClock = nvidiaCoreClock; - gpu_info.MemClock = nvidiaMemClock * 2; + gpu_info.MemClock = nvidiaMemClock; + } else if (nvctrlSuccess) { + getNvctrlInfo(); + gpu_info.load = nvctrl_info.load; + gpu_info.temp = nvctrl_info.temp; + gpu_info.memoryUsed = nvctrl_info.memoryUsed / (1024.f); + gpu_info.CoreClock = nvctrl_info.CoreClock; + gpu_info.MemClock = nvctrl_info.MemClock; } - + pthread_detach(gpuThread); return NULL; } diff --git a/src/gpu.h b/src/gpu.h index 1d10df4c..47ee7bb3 100644 --- a/src/gpu.h +++ b/src/gpu.h @@ -3,6 +3,7 @@ #include #include #include "nvidia_info.h" +#include "nvctrl.h" using namespace std; extern FILE *amdGpuFile, *amdTempFile, *amdGpuVramTotalFile, *amdGpuVramUsedFile, *amdGpuCoreClockFile, *amdGpuMemoryClockFile; diff --git a/src/loaders/loader_nvctrl.cpp b/src/loaders/loader_nvctrl.cpp new file mode 100644 index 00000000..2a75d8ca --- /dev/null +++ b/src/loaders/loader_nvctrl.cpp @@ -0,0 +1,95 @@ +// This is generated file. Do not modify directly. +// Path to the code generator: /home/crz/git/MangoHud/generate_library_loader.py . + +#include "loader_nvctrl.h" + +// Put these sanity checks here so that they fire at most once +// (to avoid cluttering the build output). +#if !defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) && !defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED) +#error neither LIBRARY_LOADER_NVCTRL_H_DLOPEN nor LIBRARY_LOADER_NVCTRL_H_DT_NEEDED defined +#endif +#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) && defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED) +#error both LIBRARY_LOADER_NVCTRL_H_DLOPEN and LIBRARY_LOADER_NVCTRL_H_DT_NEEDED defined +#endif + +libnvctrl_loader::libnvctrl_loader() : loaded_(false) { +} + +libnvctrl_loader::~libnvctrl_loader() { + CleanUp(loaded_); +} + +bool libnvctrl_loader::Load(const std::string& library_name) { + if (loaded_) { + return false; + } + +#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) + library_ = dlopen(library_name.c_str(), RTLD_LAZY); + if (!library_) + return false; + + XNVCTRLIsNvScreen = + reinterpret_castXNVCTRLIsNvScreen)>( + dlsym(library_, "XNVCTRLIsNvScreen")); + if (!XNVCTRLIsNvScreen) { + CleanUp(true); + return false; + } + + XNVCTRLQueryVersion = + reinterpret_castXNVCTRLQueryVersion)>( + dlsym(library_, "XNVCTRLQueryVersion")); + if (!XNVCTRLQueryVersion) { + CleanUp(true); + return false; + } + + XNVCTRLQueryAttribute = + reinterpret_castXNVCTRLQueryAttribute)>( + dlsym(library_, "XNVCTRLQueryAttribute")); + if (!XNVCTRLQueryAttribute) { + CleanUp(true); + return false; + } + + XNVCTRLQueryTargetStringAttribute = + reinterpret_castXNVCTRLQueryTargetStringAttribute)>( + dlsym(library_, "XNVCTRLQueryTargetStringAttribute")); + if (!XNVCTRLQueryTargetStringAttribute) { + CleanUp(true); + return false; + } + + XNVCTRLQueryTargetAttribute64 = + reinterpret_castXNVCTRLQueryTargetAttribute64)>( + dlsym(library_, "XNVCTRLQueryTargetAttribute64")); + if (!XNVCTRLQueryTargetAttribute64) { + CleanUp(true); + return false; + } + +#endif + +#if defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED) + XNVCTRLQueryVersion = &::XNVCTRLQueryVersion; + XNVCTRLQueryAttribute = &::XNVCTRLQueryAttribute; + +#endif + + loaded_ = true; + return true; +} + +void libnvctrl_loader::CleanUp(bool unload) { +#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) + if (unload) { + dlclose(library_); + library_ = NULL; + } +#endif + loaded_ = false; + XNVCTRLQueryVersion = NULL; + XNVCTRLQueryAttribute = NULL; + +} diff --git a/src/loaders/loader_nvctrl.h b/src/loaders/loader_nvctrl.h new file mode 100644 index 00000000..d16b4029 --- /dev/null +++ b/src/loaders/loader_nvctrl.h @@ -0,0 +1,44 @@ +// This is generated file. Do not modify directly. +// Path to the code generator: /home/crz/git/MangoHud/generate_library_loader.py . + +#ifndef LIBRARY_LOADER_NVCTRL_H +#define LIBRARY_LOADER_NVCTRL_H +#define Bool bool +#include +#include "NVCtrl/NVCtrlLib.h" +#define LIBRARY_LOADER_NVCTRL_H_DLOPEN + + +#include +#include + +class libnvctrl_loader { + public: + libnvctrl_loader(); + libnvctrl_loader(const std::string& library_name) { Load(library_name); } + ~libnvctrl_loader(); + + bool Load(const std::string& library_name); + bool IsLoaded() { return loaded_; } + + decltype(&::XNVCTRLIsNvScreen) XNVCTRLIsNvScreen; + decltype(&::XNVCTRLQueryVersion) XNVCTRLQueryVersion; + decltype(&::XNVCTRLQueryAttribute) XNVCTRLQueryAttribute; + decltype(&::XNVCTRLQueryTargetStringAttribute) XNVCTRLQueryTargetStringAttribute; + decltype(&::XNVCTRLQueryTargetAttribute64) XNVCTRLQueryTargetAttribute64; + + private: + void CleanUp(bool unload); + +#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) + void* library_; +#endif + + bool loaded_; + + // Disallow copy constructor and assignment operator. + libnvctrl_loader(const libnvctrl_loader&); + void operator=(const libnvctrl_loader&); +}; + +#endif // LIBRARY_LOADER_NVCTRL_H diff --git a/src/meson.build b/src/meson.build index 157a7dc1..48528f72 100644 --- a/src/meson.build +++ b/src/meson.build @@ -44,6 +44,7 @@ vklayer_files = files( 'font_unispace.c', 'cpu.cpp', 'loaders/loader_nvml.cpp', + 'loaders/loader_nvctrl.cpp', 'nvml.cpp', 'file_utils.cpp', 'memory.cpp', @@ -52,6 +53,7 @@ vklayer_files = files( 'gpu.cpp', 'notify.cpp', 'elfhacks.cpp', + 'nvctrl.cpp', ) opengl_files = files( diff --git a/src/nvctrl.cpp b/src/nvctrl.cpp new file mode 100644 index 00000000..5c6e1411 --- /dev/null +++ b/src/nvctrl.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "nvctrl.h" +#include "loaders/loader_nvctrl.h" +#include "string_utils.h" + +typedef std::unordered_map string_map; + +Display *display = XOpenDisplay(NULL); +libnvctrl_loader nvctrl("libXNVCtrl.so"); + +struct nvctrlInfo nvctrl_info; +bool nvctrlSuccess = false; + +bool checkXNVCtrl() +{ + if (nvctrl.IsLoaded()) { + nvctrlSuccess = nvctrl.XNVCTRLIsNvScreen(display, 0); + return nvctrlSuccess; + } + return false; +} + +void parse_token(std::string token, string_map& options) { + std::string param, value; + + size_t equal = token.find("="); + if (equal == std::string::npos) + return; + + value = token.substr(equal+1); + + param = token.substr(0, equal); + trim(param); + trim(value); + //std::cerr << __func__ << ": " << param << "=" << value << std::endl; + if (!param.empty()) + options[param] = value; +} + +char* get_attr_target_string(int attr, int target_type, int target_id) { + char* c = nullptr; + + if (!nvctrl.XNVCTRLQueryTargetStringAttribute(display, target_type, target_id, 0, attr, &c)) { + fprintf(stderr, "Failed to query attribute '%d'.\n", attr); + + } + return c; +} + +void getNvctrlInfo(){ + string_map params; + std::string token; + + int enums[] = { + NV_CTRL_STRING_GPU_UTILIZATION, + NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS, + 0 // keep null + }; + + for (size_t i=0; enums[i]; i++) { + char* str = get_attr_target_string(enums[i], NV_CTRL_TARGET_TYPE_GPU, 0); + if (!str) + continue; + + std::stringstream ss (str); + while (std::getline(ss, token, ',')) { + parse_token(token, params); + } + free(str); + } + + if (!try_stoi(nvctrl_info.load, params["graphics"])) + nvctrl_info.load = 0; + if (!try_stoi(nvctrl_info.CoreClock, params["nvclock"])) + nvctrl_info.CoreClock = 0; + if (!try_stoi(nvctrl_info.MemClock, params["memclock"])) + nvctrl_info.MemClock = 0; + + int64_t temp = 0; + nvctrl.XNVCTRLQueryTargetAttribute64(display, + NV_CTRL_TARGET_TYPE_GPU, + 0, + 0, + NV_CTRL_GPU_CORE_TEMPERATURE, + &temp); + nvctrl_info.temp = temp; + + int64_t memtotal = 0; + nvctrl.XNVCTRLQueryTargetAttribute64(display, + NV_CTRL_TARGET_TYPE_GPU, + 0, + 0, + NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY, + &memtotal); + nvctrl_info.memoryTotal = memtotal; + + int64_t memused = 0; + nvctrl.XNVCTRLQueryTargetAttribute64(display, + NV_CTRL_TARGET_TYPE_GPU, + 0, + 0, + NV_CTRL_USED_DEDICATED_GPU_MEMORY, + &memused); + nvctrl_info.memoryUsed = memused; +} \ No newline at end of file diff --git a/src/nvctrl.h b/src/nvctrl.h new file mode 100644 index 00000000..3de9052f --- /dev/null +++ b/src/nvctrl.h @@ -0,0 +1,14 @@ +struct nvctrlInfo{ + int load; + int temp; + float memoryUsed; + float memoryTotal; + int MemClock; + int CoreClock; +}; + +extern struct nvctrlInfo nvctrl_info; +extern bool nvctrlSuccess; +bool checkXNVCtrl(void); +void getNvctrlInfo(void); +char *get_attr_target_string(int attr, int target_type, int target_id); \ No newline at end of file diff --git a/src/nvidia_info.h b/src/nvidia_info.h index a3e47cc8..b914e42f 100644 --- a/src/nvidia_info.h +++ b/src/nvidia_info.h @@ -9,5 +9,5 @@ extern struct nvmlUtilization_st nvidiaUtilization; extern struct nvmlMemory_st nvidiaMemory; extern bool nvmlSuccess; -bool checkNvidia(void); -void getNvidiaInfo(void); \ No newline at end of file +bool checkNVML(void); +void getNVMLInfo(void); \ No newline at end of file diff --git a/src/nvml.cpp b/src/nvml.cpp index 7ff8a655..66429dc0 100644 --- a/src/nvml.cpp +++ b/src/nvml.cpp @@ -10,7 +10,7 @@ unsigned int nvidiaTemp, nvidiaCoreClock, nvidiaMemClock; struct nvmlUtilization_st nvidiaUtilization; struct nvmlMemory_st nvidiaMemory {}; -bool checkNvidia(){ +bool checkNVML(){ if (nvml.IsLoaded()){ result = nvml.nvmlInit(); if (NVML_SUCCESS != result) { @@ -25,11 +25,14 @@ bool checkNvidia(){ return false; } -void getNvidiaInfo(){ +void getNVMLInfo(){ + nvmlReturn_t response; nvml.nvmlDeviceGetHandleByIndex(0, &nvidiaDevice); - nvml.nvmlDeviceGetUtilizationRates(nvidiaDevice, &nvidiaUtilization); + response = nvml.nvmlDeviceGetUtilizationRates(nvidiaDevice, &nvidiaUtilization); nvml.nvmlDeviceGetTemperature(nvidiaDevice, NVML_TEMPERATURE_GPU, &nvidiaTemp); nvml.nvmlDeviceGetMemoryInfo(nvidiaDevice, &nvidiaMemory); nvml.nvmlDeviceGetClockInfo(nvidiaDevice, NVML_CLOCK_GRAPHICS, &nvidiaCoreClock); nvml.nvmlDeviceGetClockInfo(nvidiaDevice, NVML_CLOCK_MEM, &nvidiaMemClock); + if (response == NVML_ERROR_NOT_SUPPORTED) + nvmlSuccess = false; } \ No newline at end of file diff --git a/src/overlay.cpp b/src/overlay.cpp index 18419b1f..fb2704ff 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -782,7 +782,14 @@ void init_gpu_stats(uint32_t& vendorID, overlay_params& params) // NVIDIA or Intel but maybe has Optimus if (vendorID == 0x8086 || vendorID == 0x10de) { - if ((params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = checkNvidia())) { + + if (checkNVML()) + getNVMLInfo(); + + if (!nvmlSuccess) + checkXNVCtrl(); + + if ((params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = (nvmlSuccess || nvctrlSuccess))) { vendorID = 0x10de; } } diff --git a/src/string_utils.h b/src/string_utils.h index 1f1bf8e3..e0dc1cef 100644 --- a/src/string_utils.h +++ b/src/string_utils.h @@ -84,7 +84,9 @@ static bool try_stoi(int& val, const std::string& str, std::size_t* pos = 0, int val = std::stoi(str, pos, base); return true; } catch (std::invalid_argument& e) { +#ifndef NDEBUG std::cerr << __func__ << ": invalid argument: '" << str << "'" << std::endl; +#endif } return false; } @@ -95,7 +97,9 @@ static bool try_stoull(unsigned long long& val, const std::string& str, std::siz val = std::stoull(str, pos, base); return true; } catch (std::invalid_argument& e) { +#ifndef NDEBUG std::cerr << __func__ << ": invalid argument: '" << str << "'" << std::endl; +#endif } return false; }