Add liquid cooling stats

pull/1247/head
Makevelli 4 weeks ago
parent 4d0b1e1fb8
commit bdccf00195

@ -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`<br>`cpu_color`<br>`vram_color`<br>`ram_color`<br>`io_color`<br>`engine_color`<br>`frametime_color`<br>`background_color`<br>`text_color`<br>`media_player_color` | Change default colors: `gpu_color=RRGGBB` |
| `gpu_color`<br>`cpu_color`<br>`vram_color`<br>`ram_color`<br>`io_color`<br>`engine_color`<br>`frametime_color`<br>`background_color`<br>`text_color`<br>`media_player_color`<br>`liquid_color` | Change default colors: `gpu_color=RRGGBB` |
| `gpu_core_clock`<br>`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.

@ -101,6 +101,7 @@ void imgui_init()
init_system_info();
cfg_inited = true;
init_cpu_stats(params);
init_liquid_stats(params);
}
//static

@ -20,6 +20,7 @@
#include <IconsForkAwesome.h>
#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<WatercoolingDevice> 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<std::string, std::string>& optio
{"refresh_rate", {refresh_rate}},
{"winesync", {winesync}},
{"present_mode", {present_mode}},
{"network", {network}}
{"network", {network}},
{"liquid", {liquid_stats}}
};

@ -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, ...);

@ -0,0 +1,465 @@
#include "liquid.h"
#include <iostream>
#include "file_utils.h"
#include <spdlog/spdlog.h>
#include <filesystem.h>
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<std::pair<std::string, std::vector<std::string>>> parse_liquid_additional_sensors(const std::string &s)
{
std::vector<std::pair<std::string, std::vector<std::string>>> 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<std::string> 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<std::string, std::vector<std::string>> (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<std::string> 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<std::string> possibleDevices;
switch (type)
{
case TEMP:
possibleDevices = std::vector<std::string> {"d5next", "highflownext"};
break;
case FLOW:
possibleDevices = std::vector<std::string> {"highflownext"};
break;
case POWER:
// possibleDevices = std::vector<std::string> {"highflownext"};
break;
case RPM:
// possibleDevices = std::vector<std::string> {"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<std::pair<std::string, std::vector<std::string>>> list)
{
std::vector<std::pair<std::string, std::vector<std::string>>> 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<sensor> tempSensors;
std::vector<sensor> flowSensors;
std::vector<sensor> powerSensors;
std::vector<sensor> 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<sensor> 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<std::string> tempDevices, std::vector<std::string> flowDevices, std::string additionalSensors)//std::vector<std::pair<std::string, std::vector<std::string>>> 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> liquidStats;

@ -0,0 +1,46 @@
#pragma once
#ifndef MANGOHUD_LIQUID_H
#define MANGOHUD_LIQUID_H
#include <cstdio>
#include <memory>
#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<sensor> sensors;
};
class LiquidStats
{
public:
LiquidStats();
~LiquidStats();
void AddDeviceAndSensor(std::vector<std::string>, Type type);
void AddAdditionalSensors(std::string s); //(std::vector<std::pair<std::string, std::vector<std::string>>>)
void SortSensors();
bool Init(std::vector<std::string> tempDevices, std::vector<std::string> flowDevices, std::string additionalSensors); //std::vector<std::pair<std::string, std::vector<std::string>>> additionalSensors
bool Update();
bool ReadInputFile(struct sensor sensor, float &input);
float GetTemp();
int GetDeviceCount() const;
std::vector<WatercoolingDevice> GetDevicesData() const;
private:
std::vector<WatercoolingDevice> devices;
};
extern std::unique_ptr<LiquidStats> liquidStats;
#endif // MANGOHUD_LIQUID_H

@ -93,7 +93,8 @@ if is_unixy
'intel.cpp',
'msm.cpp',
'net.cpp',
'shell.cpp'
'shell.cpp',
'liquid.cpp'
)
opengl_files = files(

@ -27,6 +27,7 @@
#include "intel.h"
#include "msm.h"
#include "net.h"
#include "liquid.h"
#ifdef __linux__
#include <libgen.h>
@ -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<LiquidStats>();
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;

@ -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);

@ -29,6 +29,7 @@
#include "blacklist.h"
#include "mesa/util/os_socket.h"
#include "file_utils.h"
#include "liquid.h"
#ifdef HAVE_X11
#include <X11/keysym.h>
@ -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<unsigned *, 23> colors = {
std::array<unsigned *, 24> colors = {
&params->cpu_color,
&params->gpu_color,
&params->vram_color,
@ -899,6 +907,7 @@ parse_overlay_config(struct overlay_params *params,
&params->fps_color[2],
&params->text_outline_color,
&params->network_color,
&params->liquid_color
};
for (auto color : colors){

@ -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<unsigned> gpu_load_color;
std::vector<unsigned> cpu_load_color;
std::vector<unsigned> 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<std::string> blacklist;
unsigned autostart_log;
std::vector<std::string> media_player_format;
@ -310,6 +316,8 @@ struct overlay_params {
std::string custom_text;
std::string config_file_path;
std::unordered_map<std::string,std::string> options;
std::string liquid_additional_sensors;
std::vector<std::string> liquid_temp, liquid_flow;
int permit_upload;
int fsr_steam_sharpness;
unsigned short fcat_screen_edge;

@ -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

@ -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"){

Loading…
Cancel
Save