From bdccf00195af8cd5e799a3febc42bd94d2695679 Mon Sep 17 00:00:00 2001 From: Makevelli Date: Sat, 13 Apr 2024 14:11:52 +0300 Subject: [PATCH] Add liquid cooling stats --- README.md | 7 +- src/gl/gl_hud.cpp | 1 + src/hud_elements.cpp | 84 +++++++- src/hud_elements.h | 5 +- src/liquid.cpp | 465 +++++++++++++++++++++++++++++++++++++++++ src/liquid.h | 46 ++++ src/meson.build | 3 +- src/overlay.cpp | 16 ++ src/overlay.h | 1 + src/overlay_params.cpp | 11 +- src/overlay_params.h | 12 +- src/string_utils.h | 5 + src/vulkan.cpp | 1 + 13 files changed, 650 insertions(+), 7 deletions(-) create mode 100644 src/liquid.cpp create mode 100644 src/liquid.h diff --git a/README.md b/README.md index 8f26753c..7e5c8f83 100644 --- a/README.md +++ b/README.md @@ -365,7 +365,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu | `refresh_rate` | Display the current refresh rate (only works in gamescope) | | `full` | Enable most of the toggleable parameters (currently excludes `histogram`) | | `gamemode` | Show if GameMode is on | -| `gpu_color`
`cpu_color`
`vram_color`
`ram_color`
`io_color`
`engine_color`
`frametime_color`
`background_color`
`text_color`
`media_player_color` | Change default colors: `gpu_color=RRGGBB` | +| `gpu_color`
`cpu_color`
`vram_color`
`ram_color`
`io_color`
`engine_color`
`frametime_color`
`background_color`
`text_color`
`media_player_color`
`liquid_color` | Change default colors: `gpu_color=RRGGBB` | | `gpu_core_clock`
`gpu_mem_clock`| Display GPU core/memory frequency | | `gpu_fan` | GPU fan in rpm on AMD, FAN in percent on NVIDIA | | `gpu_load_change` | Change the color of the GPU load depending on load | @@ -431,6 +431,11 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu | `winesync` | Show wine sync method in use | | `present_mode` | Shows current vulkan [present mode](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html) or vsync status in opengl | | `network` | Show network interfaces tx and rx kb/s. You can specify interface with `network=eth0` | +|`liquid` | Enable liquid cooling stats. Devices that were checked to display the correct data: D5NEXT, HIGHFLOWNEXT, QUADRO | +|`liquid_text` | Override liquid text. Default: "Liquid" | +|`liquid_temp` | Enable coolant temperature monitoring. To display only specific devices the devices names must be specified separated by comma Eg. liquid_temp=d5next,highflownext| +|`liquid_flow` | Enable flow monitoring, displayed in L/h(Liters/hour). To display only specific devices the devices names must be specified separated by comma | +|`liquid_additional_sensors` | Enables monitoring various sensors/data from devices. Device names must be provided followed by sensor names between braces. The sensor names need to be separated by comma and need to be provided by the name they are displayed in terminal when using `sensors` command. Devices need to be sparated by semicolon. Eg. d5next {fan speed, pump speed}; highflownext {external sensor, dissipated power}; quadro {sensor 1, sensor 2} | Example: `MANGOHUD_CONFIG=cpu_temp,gpu_temp,position=top-right,height=500,font_size=32` Because comma is also used as option delimiter and needs to be escaped for values with a backslash, you can use `+` like `MANGOHUD_CONFIG=fps_limit=60+30+0` instead. diff --git a/src/gl/gl_hud.cpp b/src/gl/gl_hud.cpp index 83b962d6..c4b4594b 100644 --- a/src/gl/gl_hud.cpp +++ b/src/gl/gl_hud.cpp @@ -101,6 +101,7 @@ void imgui_init() init_system_info(); cfg_inited = true; init_cpu_stats(params); + init_liquid_stats(params); } //static diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index 0e5fed60..855bf42f 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -20,6 +20,7 @@ #include #include "version.h" #include "blacklist.h" +#include "liquid.h" #ifdef __linux__ #include "implot.h" #endif @@ -99,6 +100,7 @@ void HudElements::convert_colors(const struct overlay_params& params) HUDElements.colors.fps_value_high = convert(params.fps_color[2]); HUDElements.colors.text_outline = convert(params.text_outline_color); HUDElements.colors.network = convert(params.network_color); + HUDElements.colors.liquid = convert(params.liquid_color); ImGuiStyle& style = ImGui::GetStyle(); style.Colors[ImGuiCol_PlotLines] = convert(params.frametime_color); @@ -132,6 +134,11 @@ int HudElements::convert_to_fahrenheit(int celsius){ return fahrenheit; } +float HudElements::convert_to_fahrenheit(float celsius){ + float fahrenheit = (celsius * 9.0f / 5.0f) + 32.0f; + return fahrenheit; +} + static void ImguiNextColumnFirstItem() { ImGui::TableNextColumn(); @@ -1198,6 +1205,80 @@ void HudElements::device_battery() #endif } +void HudElements::liquid_stats() +{ +#ifdef __linux__ + if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_liquid]) + { + std::vector devices = liquidStats->GetDevicesData(); + const char* liquid_text; + liquid_text = HUDElements.params->liquid_text.c_str(); + + ImguiNextColumnFirstItem(); + HUDElements.TextColored(HUDElements.colors.liquid, "%s", liquid_text); + for (size_t i = 0; i < devices.size(); ++i) + { + if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) + { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + } + else + ImguiNextColumnOrNewRow(); + + ImGui::PushFont(HUDElements.sw_stats->font1); + HUDElements.TextColored(HUDElements.colors.liquid, "%s", devices[i].deviceName.c_str()); + ImGui::PopFont(); + for (size_t j = 0; j < devices[i].sensors.size(); ++j) + { + //ImGui::SameLine(0, 1.0f); + ImguiNextColumnOrNewRow(); + + switch (devices[i].sensors[j].type) + { + case TEMP: + if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", HUDElements.convert_to_fahrenheit(devices[i].sensors[j].input)); + else + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", devices[i].sensors[j].input); + ImGui::SameLine(0, 1.0f); + if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) + HUDElements.TextColored(HUDElements.colors.text, "°"); + else + if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) + HUDElements.TextColored(HUDElements.colors.text, "°F"); + else + HUDElements.TextColored(HUDElements.colors.text, "°C"); + break; + + case FLOW: + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", devices[i].sensors[j].input); + ImGui::SameLine(0, 1.0f); + HUDElements.TextColored(HUDElements.colors.text, "L/h"); + break; + + case POWER: + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", devices[i].sensors[j].input); + ImGui::SameLine(0, 1.0f); + ImGui::PushFont(HUDElements.sw_stats->font1); + HUDElements.TextColored(HUDElements.colors.text, "W"); + ImGui::PopFont(); + break; + + case RPM: + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%0.f", devices[i].sensors[j].input); + ImGui::SameLine(0, 1.0f); + ImGui::PushFont(HUDElements.sw_stats->font1); + HUDElements.TextColored(HUDElements.colors.text, "RPM"); + ImGui::PopFont(); + break; + } + } + } + } +#endif +} + void HudElements::frame_count(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_count]){ ImguiNextColumnFirstItem(); @@ -1525,7 +1606,8 @@ void HudElements::sort_elements(const std::pair& optio {"refresh_rate", {refresh_rate}}, {"winesync", {winesync}}, {"present_mode", {present_mode}}, - {"network", {network}} + {"network", {network}}, + {"liquid", {liquid_stats}} }; diff --git a/src/hud_elements.h b/src/hud_elements.h index f49fa54a..33b2d32d 100644 --- a/src/hud_elements.h +++ b/src/hud_elements.h @@ -62,6 +62,7 @@ class HudElements{ void legacy_elements(); void update_exec(); int convert_to_fahrenheit(int celsius); + float convert_to_fahrenheit(float celsius); static void version(); static void time(); static void gpu_stats(); @@ -103,6 +104,7 @@ class HudElements{ static void winesync(); static void present_mode(); static void network(); + static void liquid_stats(); void convert_colors(const struct overlay_params& params); void convert_colors(bool do_conv, const struct overlay_params& params); @@ -131,7 +133,8 @@ class HudElements{ fps_value_med, fps_value_high, text_outline, - network; + network, + liquid; } colors {}; void TextColored(ImVec4 col, const char *fmt, ...); diff --git a/src/liquid.cpp b/src/liquid.cpp new file mode 100644 index 00000000..f08bcb2c --- /dev/null +++ b/src/liquid.cpp @@ -0,0 +1,465 @@ +#include "liquid.h" +#include +#include "file_utils.h" +#include +#include + +LiquidStats::LiquidStats() +{ +} + +LiquidStats::~LiquidStats() +{ + for (size_t i = 0; i < this->devices.size(); ++i) + { + for (size_t j = 0; j < this->devices[i].sensors.size(); ++ j) + { + if (this->devices[i].sensors[j].source) + fclose(this->devices[i].sensors[j].source); + } + } +} + +static std::vector>> parse_liquid_additional_sensors(const std::string &s) +{ + std::vector>> vec; + char delim = ';'; + char sensorsDelim = ','; + size_t lastDelim = 0, newDelim = 0; + + while(lastDelim != s.size()) + { + if (s.at(lastDelim) == ' ') + lastDelim += 1; + newDelim = s.find_first_of(delim, lastDelim); + size_t space = s.find_first_of(" ", lastDelim); + size_t sensorListStart = s.find_first_of("{", lastDelim + 1) + 1; + size_t sensorListEnd = s.find_first_of("}", lastDelim); + + std::string deviceName; + if (space == std::string::npos || space > sensorListStart) + deviceName = s.substr(lastDelim, sensorListStart - lastDelim); + else + deviceName = s.substr(lastDelim, space - lastDelim); + + std::string sensorsSubstr = s.substr(sensorListStart, sensorListEnd - sensorListStart); + std::vector sensors; + size_t lastSensorDelim = 0, newSensorDelim; + + while (lastSensorDelim != sensorsSubstr.size()) + { + newSensorDelim = sensorsSubstr.find_first_of(sensorsDelim, lastSensorDelim); + std::string sensor; + if (sensorsSubstr.at(lastSensorDelim) == ' ') + sensor = sensorsSubstr.substr(lastSensorDelim + 1, newSensorDelim - lastSensorDelim - 1); + else + sensor = sensorsSubstr.substr(lastSensorDelim, newSensorDelim - lastSensorDelim); + + if (lastSensorDelim != newSensorDelim) + { + sensor.at(0) = toupper(sensor.at(0)); + sensors.push_back(sensor); + } + + + if (newSensorDelim == std::string::npos) + break; + + lastSensorDelim = newSensorDelim + 1; + } + + if (lastDelim != newDelim) + vec.push_back(std::pair> (deviceName, sensors)); + + if (newDelim == std::string::npos) + break; + + lastDelim = newDelim + 1; + } + return vec; +} + +static std::string findPath(std::string deviceName) +{ + std::string hwmon = "/sys/class/hwmon/"; + std::string directory; + + for (auto &path : ghc::filesystem::directory_iterator(hwmon)) + { + std::string currentEntry = path.path().filename(); + std::string currentDeviceName = read_line(hwmon + currentEntry + "/name"); + + if (currentDeviceName == deviceName) + { + directory = hwmon + currentEntry + "/"; + break; + } + } + return directory; +} + +static bool getInput(WatercoolingDevice &device, std::string label) +{ + bool add = false; + std::string input; + for (auto &path : ghc::filesystem::directory_iterator(device.directory)) + { + std::string fileName = path.path().filename(); + + if (fileName.find("_label") == std::string::npos) + continue; + + std::string currentLabel = read_line(device.directory + "/" + fileName); + + if (currentLabel.find(label) != std::string::npos) + { + auto uscore = fileName.find_first_of("_"); + + if (uscore != std::string::npos) + { + fileName.erase(uscore, std::string::npos); + input = device.directory + fileName + "_input"; + sensor newSensor; + newSensor.source = fopen(input.c_str(), "r"); + if (fileName.find("temp") != std::string::npos) + newSensor.type = TEMP; + + else if (fileName.find("fan") != std::string::npos && label == "Flow") + newSensor.type = FLOW; + + else if (fileName.find("power") != std::string::npos) + newSensor.type = POWER; + + else if (fileName.find("fan") != std::string::npos && label.find("speed") != std::string::npos) + newSensor.type = RPM; + + add = newSensor.source != nullptr; + + if (add) + device.sensors.push_back(newSensor); + else + SPDLOG_ERROR("Could not find sensor input in {}", input); + + break; + } + } + } + return add; +} + +void LiquidStats::AddDeviceAndSensor(std::vector list, Type type) +{ + std::string label; + + switch (type) + { + case TEMP: + label = "Coolant"; + break; + + case FLOW: + label = "Flow"; + break; + + case POWER: + break; + + case RPM: + break; + } + + if (list.size() == 1 && list[0] == "1") // No device name(s) provided for liquid_temp/liquid_flow param + { + std::vector possibleDevices; + switch (type) + { + case TEMP: + possibleDevices = std::vector {"d5next", "highflownext"}; + break; + + case FLOW: + possibleDevices = std::vector {"highflownext"}; + break; + + case POWER: + // possibleDevices = std::vector {"highflownext"}; + break; + + case RPM: + // possibleDevices = std::vector {"d5next"}; + break; + } + + WatercoolingDevice *device = nullptr; + + for (size_t i = 0; i < this->devices.size(); ++i) + { + for (size_t j = 0; j < possibleDevices.size(); ++j) + { + if (this->devices[i].deviceName == possibleDevices[j]) + { + device = &this->devices[i]; + getInput((*device), label); + break; + } + } + } + + if (device == nullptr) + { + for (size_t j = 0; j < possibleDevices.size(); ++j) + { + std::string deviceName = possibleDevices[j]; + std::string path = findPath(possibleDevices[j]); + + if (!path.empty()) + { + device = new WatercoolingDevice; + device->deviceName = deviceName; + device->directory = path; + getInput((*device), label); + this->devices.push_back(*device); + delete device; + } + } + } + } + else // Device name(s) provided for liquid_temp/liquid_flow, look for the specified device(s) + { + WatercoolingDevice *device = nullptr; + + for (size_t i = 0; i < list.size(); ++i) + { + for (size_t j = 0; j < this->devices.size(); ++j) + { + if (this->devices[j].deviceName == list[i]) + { + device = &this->devices[j]; + getInput((*device), label); + break; + } + } + + if (device == nullptr) + { + std::string path = findPath(list[i]); + + if (!path.empty()) + { + device = new WatercoolingDevice; + device->deviceName = list[i]; + device->directory = path; + getInput((*device), label); + this->devices.push_back(*device); + delete device; + device = nullptr; // Assign nullptr for next iteration + } + else + SPDLOG_ERROR("Could not find [{}] device [{}]", type == TEMP? "liquid_temp" : "liquid_flow", list[i]); + } + } + } +} + +void LiquidStats::AddAdditionalSensors(std::string s)//(std::vector>> list) +{ + std::vector>> list = parse_liquid_additional_sensors(s); + if (list.empty()) + return; + + if (!list[0].first.empty()) + { + for (size_t i = 0; i < list.size(); ++i) + { + std::string deviceName = list[i].first; + + WatercoolingDevice *device = nullptr; + + for (size_t j = 0; j < this->devices.size(); ++j) + { + if (this->devices[j].deviceName == deviceName) + { + device = &this->devices[j]; + for (size_t k = 0; k < list[i].second.size(); ++k) + { + bool found = getInput((*device), list[i].second[k]); + if (!found) + SPDLOG_ERROR("Could not find [{}] sensor for [{}]", list[i].second[k], deviceName); + } + break; + } + } + + if (device == nullptr) + { + std::string path = findPath(deviceName); + + if (!path.empty()) + { + device = new WatercoolingDevice; + device->deviceName = deviceName; + device->directory = path; + for (size_t j = 0; j < list[i].second.size(); ++j) + { + bool found = getInput((*device), list[i].second[j]); + if (!found) + SPDLOG_ERROR("Could not find [{}] sensor for [{}]", list[i].second[j], deviceName); + } + this->devices.push_back(*device); + delete device; + device = nullptr; + } + else + SPDLOG_ERROR("Could not find device [{}]", deviceName); + } + } + } +} + +// Order: temp, flow, power, rpm. Also when multiple sensors of the same type +// get accessed from the same device (eg. highflownext internal temp sensor and +// external temp sensor) they get grouped together +void LiquidStats::SortSensors() +{ + for (size_t i = 0; i < this->devices.size(); ++i) + { + std::vector tempSensors; + std::vector flowSensors; + std::vector powerSensors; + std::vector rpmSensors; + for (size_t j = 0; j < this->devices[i].sensors.size(); ++j) + { + switch (this->devices[i].sensors[j].type) + { + case TEMP: + tempSensors.push_back(this->devices[i].sensors[j]); + break; + + case FLOW: + flowSensors.push_back(this->devices[i].sensors[j]); + break; + + case POWER: + powerSensors.push_back(this->devices[i].sensors[j]); + break; + + case RPM: + rpmSensors.push_back(this->devices[i].sensors[j]); + break; + } + } + std::vector newSensorsVect; + for (size_t j = 0; j < tempSensors.size(); ++j) + newSensorsVect.push_back(tempSensors[j]); + + for (size_t j = 0; j < flowSensors.size(); ++j) + newSensorsVect.push_back(flowSensors[j]); + + for (size_t j = 0; j < powerSensors.size(); ++j) + newSensorsVect.push_back(powerSensors[j]); + + + for (size_t j = 0; j < rpmSensors.size(); ++j) + newSensorsVect.push_back(rpmSensors[j]); + + this->devices[i].sensors = newSensorsVect; + } +} + +bool LiquidStats::Init(std::vector tempDevices, std::vector flowDevices, std::string additionalSensors)//std::vector>> additionalSensors +{ + if (!this->devices.empty()) + return true; + + if (tempDevices.empty() && flowDevices.empty() && additionalSensors.empty()) + return false; + + AddDeviceAndSensor(tempDevices, TEMP); + AddDeviceAndSensor(flowDevices, FLOW); + AddAdditionalSensors(additionalSensors); + SortSensors(); + + if (this->devices.empty()) + { + SPDLOG_ERROR("Could not find watercooling devices"); + return false; + } + + // Changes the devices names to all uppercase letters: + for (size_t i = 0; i < this->devices.size(); ++i) + { + std::transform(this->devices[i].deviceName.begin(), this->devices[i].deviceName.end(), this->devices[i].deviceName.begin(), ::toupper); + } + + bool sensorFound = false; + + for (size_t i = 0; i < this->devices.size(); ++i) + { + if (!this->devices[i].sensors.empty()) + { + sensorFound = true; + break; + } + + } + + return sensorFound; +} + +bool LiquidStats::ReadInputFile(struct sensor sensor, float &input) +{ + if (this->devices.empty()) + return false; + + rewind(sensor.source); + fflush(sensor.source); + + bool ret = (fscanf(sensor.source, "%f", &input) == 1); + + switch(sensor.type) + { + case TEMP: + input = input / 1000.0f; + break; + + case FLOW: + input = input / 10.0f; + break; + + case POWER: + input = input / 1000000.0f; + break; + + case RPM: + break; + } + + return ret; +} + +bool LiquidStats::Update() +{ + bool ret = false; + for (size_t i = 0; i < this->devices.size(); ++i) + { + for (size_t j = 0; j < this->devices[i].sensors.size(); ++j) + { + float input = 0.0f; + ret = ReadInputFile(this->devices[i].sensors[j], input); + this->devices[i].sensors[j].input = input; + } + } + return ret; +} + +int LiquidStats::GetDeviceCount() const +{ + return this->devices.size(); +} + +std::vector< WatercoolingDevice > LiquidStats::GetDevicesData() const +{ + return this->devices; +} + +std::unique_ptr liquidStats; diff --git a/src/liquid.h b/src/liquid.h new file mode 100644 index 00000000..c558906e --- /dev/null +++ b/src/liquid.h @@ -0,0 +1,46 @@ +#pragma once +#ifndef MANGOHUD_LIQUID_H +#define MANGOHUD_LIQUID_H + +#include +#include +#include "string_utils.h" + +enum Type {TEMP, FLOW, POWER, RPM}; + +struct sensor +{ + FILE *source = nullptr; + float input; + //int intInput; + Type type; +}; + +struct WatercoolingDevice +{ + std::string deviceName, directory; + std::vector sensors; +}; + +class LiquidStats +{ +public: + LiquidStats(); + ~LiquidStats(); + void AddDeviceAndSensor(std::vector, Type type); + void AddAdditionalSensors(std::string s); //(std::vector>>) + void SortSensors(); + bool Init(std::vector tempDevices, std::vector flowDevices, std::string additionalSensors); //std::vector>> additionalSensors + bool Update(); + bool ReadInputFile(struct sensor sensor, float &input); + float GetTemp(); + int GetDeviceCount() const; + std::vector GetDevicesData() const; + +private: + std::vector devices; +}; + +extern std::unique_ptr liquidStats; + +#endif // MANGOHUD_LIQUID_H diff --git a/src/meson.build b/src/meson.build index 9698b5b8..176fc227 100644 --- a/src/meson.build +++ b/src/meson.build @@ -93,7 +93,8 @@ if is_unixy 'intel.cpp', 'msm.cpp', 'net.cpp', - 'shell.cpp' + 'shell.cpp', + 'liquid.cpp' ) opengl_files = files( diff --git a/src/overlay.cpp b/src/overlay.cpp index 0b8776d3..4070f3ea 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -27,6 +27,7 @@ #include "intel.h" #include "msm.h" #include "net.h" +#include "liquid.h" #ifdef __linux__ #include @@ -161,6 +162,11 @@ void update_hw_info(const struct overlay_params& params, uint32_t vendorID) getIoStats(g_io_stats); #endif +#ifdef __linux__ + if(params.enabled[OVERLAY_PARAM_ENABLED_liquid]) + liquidStats->Update(); +#endif + currentLogData.gpu_load = gpu_info.load; currentLogData.gpu_temp = gpu_info.temp; currentLogData.gpu_core_clock = gpu_info.CoreClock; @@ -757,6 +763,16 @@ void init_cpu_stats(overlay_params& params) #endif } +void init_liquid_stats(overlay_params& params) +{ +#ifdef __linux__ + liquidStats = std::make_unique(); + auto& enabled = params.enabled; + enabled[OVERLAY_PARAM_ENABLED_liquid] = liquidStats->Init(params.liquid_temp, params.liquid_flow, params.liquid_additional_sensors) + && enabled[OVERLAY_PARAM_ENABLED_liquid]; +#endif +} + struct pci_bus { int domain; int bus; diff --git a/src/overlay.h b/src/overlay.h index 8b53285c..05d8da65 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -103,6 +103,7 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru void update_hw_info(const struct overlay_params& params, uint32_t vendorID); void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_params& params); void init_cpu_stats(overlay_params& params); +void init_liquid_stats(overlay_params& params); void check_keybinds(overlay_params& params, uint32_t vendorID); void init_system_info(void); void FpsLimiter(struct fps_limit& stats); diff --git a/src/overlay_params.cpp b/src/overlay_params.cpp index eb1d4c18..5f274454 100644 --- a/src/overlay_params.cpp +++ b/src/overlay_params.cpp @@ -29,6 +29,7 @@ #include "blacklist.h" #include "mesa/util/os_socket.h" #include "file_utils.h" +#include "liquid.h" #ifdef HAVE_X11 #include @@ -474,6 +475,10 @@ parse_fps_metrics(const char *str){ #define parse_fcat_screen_edge(s) parse_unsigned(s) #define parse_picmip(s) parse_signed(s) #define parse_af(s) parse_signed(s) +#define parse_liquid_text(s) parse_str(s) +#define parse_liquid_temp(s) parse_str_tokenize(s) +#define parse_liquid_flow(s) parse_str_tokenize(s) +#define parse_liquid_additional_sensors(s) get_string(s) #define parse_cpu_color(s) parse_color(s) #define parse_gpu_color(s) parse_color(s) @@ -497,6 +502,7 @@ parse_fps_metrics(const char *str){ #define parse_fps_value(s) parse_load_value(s) #define parse_fps_color(s) parse_load_color(s) #define parse_battery_color(s) parse_color(s) +#define parse_liquid_color(s) parse_color(s) #define parse_media_player_format(s) parse_str_tokenize(s, ";", false) #define parse_fsr_steam_sharpness(s) parse_float(s) #define parse_text_outline_color(s) parse_color(s) @@ -782,6 +788,8 @@ static void set_param_defaults(struct overlay_params *params){ params->table_columns = 3; params->text_outline_color = 0x000000; params->text_outline_thickness = 1.5; + params->liquid_color = 0x3fcbd4; + params->liquid_text = "Liquid"; } void @@ -875,7 +883,7 @@ parse_overlay_config(struct overlay_params *params, params->font_scale_media_player = 0.55f; // Convert from 0xRRGGBB to ImGui's format - std::array colors = { + std::array colors = { ¶ms->cpu_color, ¶ms->gpu_color, ¶ms->vram_color, @@ -899,6 +907,7 @@ parse_overlay_config(struct overlay_params *params, ¶ms->fps_color[2], ¶ms->text_outline_color, ¶ms->network_color, + ¶ms->liquid_color }; for (auto color : colors){ diff --git a/src/overlay_params.h b/src/overlay_params.h index dbf26838..b5f96f8d 100644 --- a/src/overlay_params.h +++ b/src/overlay_params.h @@ -114,6 +114,7 @@ typedef unsigned long KeySym; OVERLAY_PARAM_BOOL(winesync) \ OVERLAY_PARAM_BOOL(present_mode) \ OVERLAY_PARAM_BOOL(time_no_label) \ + OVERLAY_PARAM_BOOL(liquid) \ OVERLAY_PARAM_CUSTOM(fps_sampling_period) \ OVERLAY_PARAM_CUSTOM(output_folder) \ OVERLAY_PARAM_CUSTOM(output_file) \ @@ -198,6 +199,11 @@ typedef unsigned long KeySym; OVERLAY_PARAM_CUSTOM(device_battery) \ OVERLAY_PARAM_CUSTOM(fps_metrics) \ OVERLAY_PARAM_CUSTOM(network) \ + OVERLAY_PARAM_CUSTOM(liquid_text) \ + OVERLAY_PARAM_CUSTOM(liquid_color) \ + OVERLAY_PARAM_CUSTOM(liquid_temp) \ + OVERLAY_PARAM_CUSTOM(liquid_flow) \ + OVERLAY_PARAM_CUSTOM(liquid_additional_sensors) \ enum overlay_param_position { LAYER_POSITION_TOP_LEFT, @@ -272,7 +278,7 @@ struct overlay_params { int64_t log_duration, log_interval; unsigned cpu_color, gpu_color, vram_color, ram_color, engine_color, io_color, frametime_color, background_color, - text_color, wine_color, battery_color, network_color; + text_color, wine_color, battery_color, network_color, liquid_color; std::vector gpu_load_color; std::vector cpu_load_color; std::vector gpu_load_value; @@ -299,7 +305,7 @@ struct overlay_params { std::string time_format, output_folder, output_file; std::string pci_dev; std::string media_player_name; - std::string cpu_text, gpu_text, fps_text; + std::string cpu_text, gpu_text, fps_text, liquid_text; std::vector blacklist; unsigned autostart_log; std::vector media_player_format; @@ -310,6 +316,8 @@ struct overlay_params { std::string custom_text; std::string config_file_path; std::unordered_map options; + std::string liquid_additional_sensors; + std::vector liquid_temp, liquid_flow; int permit_upload; int fsr_steam_sharpness; unsigned short fcat_screen_edge; diff --git a/src/string_utils.h b/src/string_utils.h index 8751d84e..72a72518 100644 --- a/src/string_utils.h +++ b/src/string_utils.h @@ -144,6 +144,11 @@ static void trim_char(char* str) { memmove(str, ptr, len + 1); } +static std::string get_string(const std::string &s) +{ + return s; +} + #pragma GCC diagnostic pop #endif //MANGOHUD_STRING_UTILS_H diff --git a/src/vulkan.cpp b/src/vulkan.cpp index f205b80a..6e5672d2 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -1957,6 +1957,7 @@ static VkResult overlay_CreateInstance( #endif init_cpu_stats(instance_data->params); + init_liquid_stats(instance_data->params); // Adjust height for DXVK/VKD3D version number if (engineName == "DXVK" || engineName == "VKD3D"){