Compare commits

..

No commits in common. 'master' and 'v0.7.0-rc1' have entirely different histories.

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: FlightlessMango
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://www.paypal.me/flightlessmango

@ -28,7 +28,7 @@ jobs:
cd pkgbuild
pkgver=$(git describe --tags | sed -r 's/^v//;s/([^-]*-g)/r\1/;s/-/./g')
sed -i "s/pkgver=.*/pkgver=$pkgver/g" PKGBUILD
sudo -u nobody -- sh -c "makepkg -fsCc --noconfirm"
sudo -u nobody -- sh -c "makepkg -fsiCc --noconfirm"
- name: Edit release and add files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -2,6 +2,11 @@ name: Build release package
on:
release:
types: [published]
# push:
# tags: ["v*"]
# branches:
# - main
workflow_dispatch:
jobs:
build:
@ -11,16 +16,9 @@ jobs:
- uses: actions/checkout@v3
- name: Install build tools
run: |
set -x
sudo dpkg --add-architecture i386
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages focal main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt -y install gcc-multilib g++-multilib ninja-build python3-setuptools \
python3-wheel mesa-common-dev libxnvctrl-dev libdbus-1-dev \
python3-numpy python3-matplotlib unzip hub libxkbcommon-dev libwayland-dev wget unzip \
libxkbcommon-dev:i386 libwayland-dev:i386 gh
sudo pip3 --no-input install 'meson>=0.60' mako
sudo apt install gcc-multilib g++-multilib ninja-build python3-setuptools python3-wheel mesa-common-dev libxnvctrl-dev libdbus-1-dev python3-numpy python3-matplotlib unzip
sudo pip3 install 'meson>=0.60' mako
wget https://github.com/KhronosGroup/glslang/releases/download/SDK-candidate-26-Jul-2020/glslang-master-linux-Release.zip
unzip glslang-master-linux-Release.zip bin/glslangValidator
sudo install -m755 bin/glslangValidator /usr/local/bin/
@ -37,25 +35,31 @@ jobs:
else
echo "##[set-output name=short-sha;]$(git rev-parse --short "$GITHUB_SHA")"
fi
echo "##[set-output name=artifact-metadata;]$ARTIFACT_NAME"
- name: Build and package
echo "##[set-output name=artifact-metadata;]${ARTIFACT_NAME}"
id: git-vars
- name: Build release package
run: |
./build-source.sh
./build.sh build -Dwerror=true package release
- name: Upload assets to release
if: github.event.action == 'published'
- name: Upload release
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag_name="${GITHUB_REF##*/}"
for pkg in ./build/*.tar.*; do
gh release upload "$tag_name" "$pkg" --clobber
assets=()
for asset in ./MangoHud-*-Source*.tar.*; do
assets+=("-a" "$asset")
done
for asset in ./build/MangoHud-*.tar.*; do
assets+=("-a" "$asset")
done
tag_name="${GITHUB_REF##*/}"
hub release edit "${assets[@]}" -m "" "$tag_name"
#hub release create "${assets[@]}" -m "$tag_name" "$tag_name"
- name: Upload artifact
uses: actions/upload-artifact@v3
continue-on-error: true
with:
name: MangoHud-${{steps.git-vars.outputs.artifact-metadata}}
path: ${{runner.workspace}}/MangoHud/build/MangoHud-*tar.gz
retention-days: 30
retention-days: 30

@ -11,13 +11,11 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Run build-source.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -x
sudo apt update
sudo apt -y install gcc g++ ninja-build python3-pip python3-setuptools python3-wheel pkg-config mesa-common-dev libx11-dev libxnvctrl-dev libdbus-1-dev glslang-tools hub libxkbcommon-dev libwayland-dev wget unzip
sudo pip3 --no-input install 'meson>=0.60' mako
sudo apt install gcc g++ ninja-build python3-pip python3-setuptools python3-wheel pkg-config mesa-common-dev libx11-dev libxnvctrl-dev libdbus-1-dev glslang-tools
sudo pip3 install 'meson>=0.60' mako
./build-source.sh
assets=()
for asset in ./MangoHud-*-Source*.tar.*; do
@ -26,10 +24,6 @@ jobs:
tag_name="${GITHUB_REF##*/}"
hub release edit "${assets[@]}" -m "" "$tag_name"
#hub release create "${assets[@]}" -m "$tag_name" "$tag_name"
- name: Upload artifact
uses: actions/upload-artifact@v3
continue-on-error: true
with:
name: MangoHud-${{steps.git-vars.outputs.artifact-metadata}}
path: ${{runner.workspace}}/MangoHud/build/MangoHud-*tar.gz
retention-days: 30
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -28,8 +28,7 @@ jobs:
libglew-dev \
libglfw3-dev \
libwayland-dev \
libxnvctrl-dev \
libxkbcommon-dev
libxnvctrl-dev
sudo pip3 install 'meson>=0.60'
- name: 'Install clang'
if: ${{ (matrix.compiler == 'clang') }}

1
.gitignore vendored

@ -42,7 +42,6 @@ subprojects/Vulkan-Headers-*/
subprojects/imgui-*/
subprojects/spdlog-*/
subprojects/nlohmann_json-*/
subprojects/implot-*/
#GNU Global Metadata
**/GPATH

@ -21,14 +21,14 @@ A Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and m
- [Normal usage](#normal-usage)
- [OpenGL](#opengl)
- [Hud configuration](#hud-configuration)
- [Environment Variables: **`MANGOHUD_CONFIG`**, **`MANGOHUD_CONFIGFILE`**, and **`MANGOHUD_PRESETSFILE`**](#environment-variables)
- [Environment Variables: **`MANGOHUD_CONFIG`** and **`MANGOHUD_CONFIGFILE`**](#environment-variables-mangohud_config-and-mangohud_configfile)
- [Vsync](#vsync)
- [OpenGL Vsync](#opengl-vsync)
- [Vulkan Vsync](#vulkan-vsync)
- [Keybindings](#keybindings)
- [Workarounds](#workarounds)
- [FPS logging](#fps-logging)
- [Online visualization: FlightlessMango.com](#online-visualization-flightlessmangocom)
- [Online viualization: FlightlessMango.com](#online-viualization-flightlessmangocom)
- [Local visualization: `mangoplot`](#local-visualization-mangoplot)
## Installation - Build From Source
@ -76,8 +76,6 @@ Install necessary development packages.
- X11 (libx11-dev)
- XNVCtrl (libxnvctrl-dev), optional, use `-Dwith_xnvctrl=disabled` option with `meson` to disable
- D-Bus (libdbus-1-dev), optional, use `-Dwith_dbus=disabled` option with `meson` to disable
- wayland-client
- xcbcommon
Python 3 libraries:
@ -291,14 +289,12 @@ You can find an example config in /usr/share/doc/mangohud
---
### Environment Variables
### Environment Variables: **`MANGOHUD_CONFIG`** and **`MANGOHUD_CONFIGFILE`**
You can also customize the hud by using the `MANGOHUD_CONFIG` environment variable while separating different options with a comma. This takes priority over any config file.
You can also specify configuration file with `MANGOHUD_CONFIGFILE=/path/to/config` for applications whose names are hard to guess (java, python etc).
You can also specify presets file with `MANGOHUD_PRESETSFILE=/path/to/config`. This is especially useful when running mangohud in a sandbox such as flatpak.
A partial list of parameters are below. See the config file for a complete list.
Parameters that are enabled by default have to be explicitly disabled. These (currently) are `fps`, `frame_timing`, `cpu_stats` (cpu load), `gpu_stats` (gpu load), and each can be disabled by setting the corresponding variable to 0 (e.g., fps=0).
@ -332,8 +328,6 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `custom_text_center` | Display a custom text centered useful for a header e.g `custom_text_center=FlightLessMango Benchmarks` |
| `custom_text` | Display a custom text e.g `custom_text=Fsync enabled` |
| `debug` | Shows the graph of gamescope app frametimes and latency (only on gamescope obviously) |
| `device_battery_icon` | Display wirless device battery icon. |
| `device_battery` | Display wireless device battery percent. Currently supported arguments `gamepad` and `mouse` e.g `device_battery=gamepad,mouse` |
| `dynamic_frame_timing` | This changes frame_timing y-axis to correspond with the current maximum and minimum frametime instead of being a static 0-50 |
| `engine_short_names` | Display a short version of the used engine (e.g. `OGL` instead of `OpenGL`) |
| `engine_version` | Display OpenGL or vulkan and vulkan-based render engine's version |
@ -356,18 +350,17 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `fps_limit` | Limit the apps framerate. Comma-separated list of one or more FPS values. `0` means unlimited |
| `fps_only` | Show FPS only. ***Not meant to be used with other display params*** |
| `fps_sampling_period=` | Time interval between two sampling points for gathering the FPS in milliseconds. Default is `500` |
| `fps_value` | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` |
| `fps_metrics` | Takes a list of decimal values or the value avg, e.g `avg,0.001` |
| `fps_value=` | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` |
| `frame_count` | Display frame count |
| `frametime` | Display frametime next to FPS text |
| `fsr` | Display the status of FSR (only works in gamescope) |
| `hdr` | Display the status of HDR (only works in gamescope) |
| `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 |
| `gamepad_battery_icon` | Display gamepad battery percent with icon. *Enabled by default* |
| `gamepad_battery` | Display battey of wireless gamepads (xone/xpadneo/ds4) |
| `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_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_fan` | GPU fan in rpm (only works on AMD GPUs) |
| `gpu_load_change` | Change the color of the GPU load depending on load |
| `gpu_load_color` | Set the colors for the gpu load change low,medium and high. e.g `gpu_load_color=0000FF,00FFFF,FF00FF` |
| `gpu_load_value` | Set the values for medium and high load e.g `gpu_load_value=50,90` |
@ -411,10 +404,8 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `text_outline_color=` | Set the color of `text_outline`. Default = `000000` |
| `text_outline_thickness=` | Set the thickness of `text_outline`. Default = `1.5` |
| `throttling_status` | Show if GPU is throttling based on Power, current, temp or "other" (Only shows if throttling is currently happening). Currently disabled by default for Nvidia as it causes lag on 3000 series |
| `throttling_status_graph` | Same as `throttling_status` but displays throttling in the frametime graph and only power and temp throttling |
| `time`<br>`time_format=%T` | Display local time. See [std::put_time](https://en.cppreference.com/w/cpp/io/manip/put_time) for formatting help. NOTE: Sometimes apps may set `TZ` (timezone) environment variable to UTC/GMT |
| `time_no_label` | Remove the label before time |
| `toggle_fps_limit` | Cycle between FPS limits (needs at least two values set with `fps_limit`). Defaults to `Shift_L+F1` |
| `toggle_fps_limit` | Cycle between FPS limits. Defaults to `Shift_L+F1` |
| `toggle_preset` | Cycle between Presets. Defaults to `Shift_R+F10` |
| `toggle_hud=`<br>`toggle_logging=` | Modifiable toggle hotkeys. Default are `Shift_R+F12` and `Shift_L+F2`, respectively |
| `toggle_hud_position` | Toggle MangoHud postion. Default is `R_Shift+F11` |
@ -428,9 +419,6 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `width=`<br>`height=` | Customizeable HUD dimensions (in pixels) |
| `wine_color` | Change color of the wine/proton text |
| `wine` | Show current Wine or Proton version in use |
| `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` |
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.
@ -481,7 +469,7 @@ When you toggle logging (default keybind is `Shift_L+F2`), a file is created wit
Log files can be visualized with two different tools: online and locally.
### Online visualization: FlightlessMango.com
### Online viualization: FlightlessMango.com
Log files can be (batch) uploaded to [FlightlessMango.com](https://flightlessmango.com/games/user_benchmarks), which will then take care of creating a frametime graph and a summary with 1% min / average framerate / 97th percentile in a table form and a horizontal bar chart form.
Notes:

@ -66,8 +66,6 @@ mangohud_install() {
/usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud_dlsym.so /usr/lib/mangohud/lib64/libMangoHud_dlsym.so
/usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so
/usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_dlsym.so /usr/lib/mangohud/lib32/libMangoHud_dlsym.so
/usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/lib/mangohud/lib64/libMangoHud_opengl.so
/usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/lib/mangohud/lib32/libMangoHud_opengl.so
/usr/bin/install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json
/usr/bin/install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86.json
/usr/bin/install -Dvm644 ./usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1

@ -1,58 +1,35 @@
#!/bin/sh
if [ "$#" -eq 0 ]; then
programname=$(basename "$0")
echo "ERROR: No program supplied"
echo
echo "Usage: $programname <program>"
exit 1
programname=`basename "$0"`
echo "ERROR: No program supplied"
echo
echo "Usage: $programname <program>"
exit 1
fi
# Add exe names newline separated to the string to disable LD_PRELOAD
DISABLE_LD_PRELOAD="cs2.sh
"
MANGOHUD_LIB_NAME="@ld_libdir_mangohud@libMangoHud_opengl.so"
if [ "$1" = "--dlsym" ]; then
MANGOHUD_LIB_NAME="@ld_libdir_mangohud@libMangoHud_dlsym.so:${MANGOHUD_LIB_NAME}"
shift # shift will only be executed if $1 is "--dlsym"
elif [ "$MANGOHUD_DLSYM" = "1" ]; then
MANGOHUD_LIB_NAME="@ld_libdir_mangohud@libMangoHud_dlsym.so:${MANGOHUD_LIB_NAME}"
MANGOHUD_LIB_NAME="@ld_libdir_mangohud@libMangoHud_dlsym.so:${MANGOHUD_LIB_NAME}"
shift
fi
if [ "$1" = "--version" ]; then
echo @version@
exit 0
echo @version@
exit 0
fi
# grab all arguments from command_line
command_line="$*"
# flag for disable_preload
disable_preload=false
# Make sure we don't append mangohud lib multiple times
# otherwise this could cause issues with steam runtime
case ":${LD_PRELOAD-}:" in
(*:$MANGOHUD_LIB_NAME:*)
;;
(*)
# Preload using the plain filenames of the libs, the dynamic linker will
# figure out whether the 32 or 64 bit version should be used
LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}${MANGOHUD_LIB_NAME}"
esac
# Check if the script name or any of the executables in DISABLE_LD_PRELOAD are in the command line
for exe in $DISABLE_LD_PRELOAD; do
if echo "$command_line" | grep -q "$exe"; then
disable_preload=true
break
fi
done
if [ "$disable_preload" = true ]; then
exec env MANGOHUD=1 "$@"
else
# Make sure we don't append mangohud lib multiple times
# otherwise, this could cause issues with the steam runtime
case ":${LD_PRELOAD-}:" in
(*:$MANGOHUD_LIB_NAME:*)
;;
(*)
# Preload using the plain filenames of the libs, the dynamic linker will
# figure out whether the 32 or 64 bit version should be used
LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}${MANGOHUD_LIB_NAME}"
esac
exec env MANGOHUD=1 LD_PRELOAD="${LD_PRELOAD}" "$@"
fi
exec env MANGOHUD=1 LD_PRELOAD="${LD_PRELOAD}" "$@"

@ -31,7 +31,7 @@ rm -r ${NAME}/subprojects/nlohmann_json-*
# remove some vulkan clutter
rm -r ${NAME}/subprojects/Vulkan-Headers-*/cmake ${NAME}/subprojects/Vulkan-Headers-*/BUILD.gn
# remove some dear imgui clutter
rm -rf ${NAME}/subprojects/imgui-*/examples
rm -rf ${NAME}/subprojects/imgui-*/examples ${NAME}/subprojects/imgui-*/misc
# compress new sources
tar -cJf ${DFSG_TAR_NAME} ${NAME}

@ -54,7 +54,7 @@ dependencies() {
for i in $DISTRO; do
echo "# Checking dependencies for \"$i\""
case $i in
*arch*|*manjaro*|*artix*|*SteamOS*)
*arch*|*manjaro*|*artix*)
MANAGER_QUERY="pacman -Q"
MANAGER_INSTALL="pacman -S"
DEPS="{${DEPS_ARCH}}"
@ -68,12 +68,12 @@ dependencies() {
dep_install
unset INSTALL
DEPS="{glibc-devel.i686,libstdc++-devel.i686,libX11-devel.i686,wayland-devel.i686,libxkbcommon-devel.i686}"
DEPS="{glibc-devel.i686,libstdc++-devel.i686,libX11-devel.i686}"
dep_install
break
;;
*debian*|*ubuntu*|*deepin*|*pop*)
*debian*|*ubuntu*|*deepin*)
MANAGER_QUERY="dpkg-query -s"
MANAGER_INSTALL="apt install"
DEPS="{${DEPS_DEBIAN}}"

@ -1,7 +1,7 @@
DEPS_ARCH="gcc,meson,pkgconf,python-mako,glslang,libglvnd,lib32-libglvnd,libxnvctrl,libdrm,python-numpy,python-matplotlib,libxkbcommon"
DEPS_FEDORA="meson,gcc,gcc-c++,libX11-devel,glslang,python3-mako,mesa-libGL-devel,libXNVCtrl-devel,dbus-devel,python3-numpy,python3-matplotlib,libstdc++-static,libstdc++-static.i686,libxkbcommon-devel,wayland-devel"
DEPS_DEBIAN="gcc,g++,gcc-multilib,g++-multilib,ninja-build,python3-pip,python3-setuptools,python3-wheel,pkg-config,mesa-common-dev,libx11-dev,libxnvctrl-dev,libdbus-1-dev,python3-numpy,python3-matplotlib,libxkbcommon-dev,libxkbcommon-dev:i386,libwayland-dev,libwayland-dev:i386"
DEPS_SOLUS="mesalib-32bit-devel,glslang,libstdc++-32bit,glibc-32bit-devel,mako,numpy,matplotlib,libxkbcommon-devel"
DEPS_ARCH="gcc,meson,pkgconf,python-mako,glslang,libglvnd,lib32-libglvnd,libxnvctrl,libdrm,python-numpy,python-matplotlib"
DEPS_FEDORA="meson,gcc,gcc-c++,libX11-devel,glslang,python3-mako,mesa-libGL-devel,libXNVCtrl-devel,dbus-devel,python3-numpy,python3-matplotlib,libstdc++-static"
DEPS_DEBIAN="gcc,g++,gcc-multilib,g++-multilib,ninja-build,python3-pip,python3-setuptools,python3-wheel,pkg-config,mesa-common-dev,libx11-dev,libxnvctrl-dev,libdbus-1-dev,python3-numpy,python3-matplotlib"
DEPS_SOLUS="mesalib-32bit-devel,glslang,libstdc++-32bit,glibc-32bit-devel,mako,numpy,matplotlib"
DEPS_SUSE="gcc-c++,gcc-c++-32bit,libpkgconf-devel,ninja,python3-pip,python3-Mako,libX11-devel,glslang-devel,glibc-devel,glibc-devel-32bit,libstdc++-devel,libstdc++-devel-32bit,Mesa-libGL-devel,dbus-1-devel,python-numpy,python-matplotlib,libxkbcommon-devel"
DEPS_SUSE="gcc-c++,gcc-c++-32bit,libpkgconf-devel,ninja,python3-pip,python3-Mako,libX11-devel,glslang-devel,glibc-devel,glibc-devel-32bit,libstdc++-devel,libstdc++-devel-32bit,Mesa-libGL-devel,dbus-1-devel,python-numpy,python-matplotlib"
DEPS_SUSE_EXTRA="libXNVCtrl-devel"

@ -62,8 +62,6 @@
### Display the current system time
# time
## removes the time label
# time_no_label
### Time formatting examples
## %H:%M
@ -87,10 +85,9 @@ gpu_stats
# gpu_load_change
# gpu_load_value=60,90
# gpu_load_color=39F900,FDFD09,B22222
## GPU fan in rpm on AMD, FAN in percent on NVIDIA
## GPU fan in rpm (only works on AMD GPUs)
# gpu_fan
## gpu_voltage only works on AMD GPUs
# gpu_voltage
# gpu_voltage (only works on AMD GPUs)
### Display the current CPU information
cpu_stats
@ -124,8 +121,8 @@ cpu_stats
### Display battery information
# battery
# battery_icon
# device_battery=gamepad,mouse
# device_battery_icon
# gamepad_battery
# gamepad_battery_icon
# battery_watt
# battery_time
@ -137,14 +134,10 @@ fps
# fps_color=B22222,FDFD09,39F900
frametime
# frame_count
## fps_metrics takes a list of decimal values or the value avg
# fps_metrics=avg,0.01
### Display GPU throttling status based on Power, current, temp or "other"
## Only shows if throttling is currently happening
throttling_status
## Same as throttling_status but displays throttling on the frametime graph
#throttling_status_graph
### Display miscellaneous information
# engine_version
@ -153,7 +146,6 @@ throttling_status
# vulkan_driver
# wine
# exec_name
# winesync
### Display loaded MangoHud architecture
# arch
@ -173,11 +165,6 @@ frame_timing
# hide_fsr_sharpness
## Shows the graph of gamescope app frametimes and latency (only on gamescope obviously)
# debug
## Display the status of HDR (only works in gamescope)
# hdr
## Display the current refresh rate (only works in gamescope)
# refresh_rate
### graphs displays one or more graphs that you chose
## seperated by ",", available graphs are
@ -212,14 +199,6 @@ frame_timing
## example: Track:;{title};By:;{artist};From:;{album}
# media_player_format=title,artist,album
### Network interface throughput
# network
## Network can take arguments but it's not required.
## without arguments it shows all interfaces
## arguments set which interfaces will be displayed
# network=eth0,wlo1
### Change the hud font size
# font_size=24
# font_scale=1.0

@ -15,7 +15,7 @@ MangoHud can be enabled for Vulkan applications by setting \fBMANGOHUD=1\fR as e
.br
To load MangoHud for any application, including OpenGL applications, the \fBmangohud\fR executable can be used. It preloads a library via ld into the application.
.br
Note: some OpenGL applications may also need dlsym hooking. This can be done by passing option \fB--dlsym\fR or by setting \fBMANGOHUD_DLSYM=1\fR as envrionment variable.
Note: some OpenGL applications may also need dlsym hooking. This can be done by passing option \fB--dlsym\fR.
.SH CONFIG
MangoHud comes with a config file which can be used to set configuration options globally or per application. The priorities of different config files are:

@ -47,10 +47,3 @@ install_data(
rename : ['MangoHud.conf.example'],
install_tag : 'doc',
)
install_data(
files('presets.conf'),
install_dir : join_paths(get_option('datadir'), 'doc', 'mangohud'),
rename : ['presets.conf.example'],
install_tag : 'doc',
)

@ -1,6 +1,6 @@
project('MangoHud',
['c', 'cpp'],
version : 'v0.7.2',
version : 'v0.6.9',
license : 'MIT',
meson_version: '>=0.60.0',
default_options : ['buildtype=release', 'c_std=c99', 'cpp_std=c++14', 'warning_level=2']
@ -27,13 +27,15 @@ pre_args = [
'-DSPDLOG_COMPILED_LIB'
]
# Always set max spdlog level, handle this using MANGOHUD_LOG_LEVEL instead.
# Define DEBUG for debug builds only (debugoptimized is not included on this one)
if get_option('buildtype') == 'debug'
pre_args += '-DDEBUG'
pre_args += '-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE'
else
pre_args += '-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG'
pre_args += '-DNDEBUG'
pre_args += '-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_' + get_option('loglevel').to_upper()
endif
# TODO: this is very incomplete
is_unixy = false
if ['linux', 'cygwin', 'gnu'].contains(host_machine.system())
@ -89,7 +91,6 @@ if is_unixy
dep_wayland_client = dependency('wayland-client',
required: get_option('with_wayland'), version : '>=1.11')
dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true)
dep_xkb = dependency('xkbcommon', required: get_option('with_wayland'))
else
dep_x11 = null_dep
dep_wayland_client = null_dep
@ -103,7 +104,6 @@ endif
if dep_wayland_client.found()
vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR']
vulkan_wsi_deps += dep_wayland_client
vulkan_wsi_deps += dep_xkb
endif
if is_unixy and not dep_x11.found() and not dep_wayland_client.found()
@ -166,18 +166,9 @@ else
dep_rt = null_dep
endif
# Commented code can be used if mangohud start using latest SDK Vulkan-Headers
# Allowing user to build mangohud using system Vulkan-Headers
#if not dependency('VulkanHeaders').found()
vkh_sp = subproject('vulkan-headers')
vk_api_xml = vkh_sp.get_variable('vulkan_api_xml')
dep_vulkan = vkh_sp.get_variable('vulkan_headers_dep')
#else
# dep_vulkan = dependency('VulkanHeaders', required: true)
# vk_api_xml = files('/usr/share/vulkan/registry/vk.xml')
#endif
vkh_sp = subproject('vulkan-headers')
vk_api_xml = vkh_sp.get_variable('vulkan_api_xml')
dep_vulkan = vkh_sp.get_variable('vulkan_headers_dep')
vk_enum_to_str = custom_target(
'vk_enum_to_str',
@ -204,9 +195,8 @@ imgui_options = [
'sdl2=disabled',
'osx=disabled',
'win=disabled',
'marmalade=disabled',
'allegro5=disabled',
'webgpu=disabled',
'sdl_renderer=disabled'
]
sizeof_ptr = cc.sizeof('void*')
@ -222,36 +212,26 @@ if get_option('mangoapp')
'glfw=enabled',
]
endif
dearimgui_dep = dependency('imgui', fallback: ['imgui'], required: true, default_options: imgui_options)
if is_unixy
implot_dep = dependency('implot', fallback: ['implot'], required: true, default_options: ['default_library=static'])
dearimgui_sp = subproject('imgui', default_options: imgui_options)
dearimgui_dep = dearimgui_sp.get_variable('imgui_dep')
spdlog_dep = cpp.find_library('spdlog', required: get_option('use_system_spdlog'))
if not spdlog_dep.found()
spdlog_sp = subproject('spdlog', default_options: [
'default_library=static',
'compile_library=true',
'werror=false',
'tests=false',
])
spdlog_dep = spdlog_sp.get_variable('spdlog_dep')
else
implot_dep = null_dep
implot_lib = static_library('nulllib', [])
endif
spdlog_options = [
'default_library=static',
'compile_library=true',
'werror=false',
'tests=disabled',
'external_fmt=disabled',
'std_format=disabled'
]
spdlog_dep = dependency('spdlog', required: false)
if get_option('use_system_spdlog').disabled() or not spdlog_dep.found()
if get_option('use_system_spdlog').enabled()
warning('spdlog depedency not found follwing back to submodule')
endif
spdlog_sp = subproject('spdlog', default_options: spdlog_options)
spdlog_dep = spdlog_sp.get_variable('spdlog_dep')
spdlog_dep = dependency('spdlog', required: true)
endif
if ['windows', 'mingw'].contains(host_machine.system())
minhook_dep = dependency('minhook', fallback: ['minhook', 'minhook_dep'], required: true)
minhook_sp = subproject('minhook')
minhook_dep = minhook_sp.get_variable('minhook_dep')
windows_deps = [
minhook_dep,
]
@ -261,7 +241,6 @@ endif
if get_option('mangoapp') or get_option('mangoapp_layer')
glfw3_dep = dependency('glfw3')
glew_dep = dependency('glew')
endif
json_dep = dependency('nlohmann_json')
@ -284,10 +263,8 @@ if get_option('tests').enabled()
),
cpp_args: ['-DTEST_ONLY'],
dependencies: [
dep_vulkan,
cmocka_dep,
spdlog_dep,
implot_dep,
dearimgui_dep
],
include_directories: inc_common)
@ -297,6 +274,4 @@ if get_option('tests').enabled()
endif
# install helper sripts
if get_option('mangoplot').enabled()
subdir('bin')
endif
subdir('bin')

@ -5,12 +5,10 @@ option('include_doc', type : 'boolean', value : true, description: 'Include the
option('with_nvml', type : 'combo', value : 'enabled', choices: ['enabled', 'system', 'disabled'], description: 'Enable NVML support')
option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support')
option('with_x11', type : 'feature', value : 'enabled')
option('with_wayland', type : 'feature', value : 'enabled')
option('with_wayland', type : 'feature', value : 'disabled')
option('with_dbus', type : 'feature', value : 'enabled')
option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build')
option('mangoapp', type: 'boolean', value : false)
option('mangohudctl', type: 'boolean', value : false)
option('mangoapp_layer', type: 'boolean', value : false)
option('tests', type: 'feature', value: 'auto', description: 'Run tests')
option('mangoplot', type: 'feature', value: 'enabled')
option('dynamic_string_tokens', type: 'boolean', value: true, description: 'Use dynamic string tokens in LD_PRELOAD')

@ -1,41 +1,36 @@
# Maintainer: Simon Hallsten <flightlessmangoyt@gmail.com>
pkgname=('mangohud' 'lib32-mangohud')
pkgver=0.7.2.rc3.r13.g5d744d3
pkgver=0.6.8.r140.g1b3f8b2
pkgrel=1
pkgdesc="Vulkan and OpenGL overlay to display performance information"
arch=('x86_64')
makedepends=('dbus' 'gcc' 'meson' 'python-mako' 'libx11' 'lib32-libx11' 'git' 'pkgconf' 'vulkan-headers')
depends=('glslang' 'libglvnd' 'lib32-libglvnd' 'glew' 'glfw-x11' 'python-numpy' 'python-matplotlib'
'libxrandr' 'libxkbcommon' 'lib32-libxkbcommon')
depends=('glslang' 'libglvnd' 'lib32-libglvnd' 'glew' 'glfw-x11' 'python-numpy' 'python-matplotlib')
replaces=('vulkan-mesa-layer-mango')
license=('MIT')
source=(
"mangohud"::"git+https://github.com/flightlessmango/MangoHud.git#branch=master"
"mangohud-minhook"::"git+https://github.com/flightlessmango/minhook.git"
"imgui-1.89.9.tar.gz::https://github.com/ocornut/imgui/archive/refs/tags/v1.89.9.tar.gz"
"imgui_1.89.9-1_patch.zip::https://wrapdb.mesonbuild.com/v2/imgui_1.89.9-1/get_patch"
"spdlog-1.14.1.tar.gz::https://github.com/gabime/spdlog/archive/refs/tags/v1.14.1.tar.gz"
"spdlog_1.14.1-1_patch.zip::https://wrapdb.mesonbuild.com/v2/spdlog_1.14.1-1/get_patch"
"imgui-v1.81.tar.gz::https://github.com/ocornut/imgui/archive/v1.81.tar.gz"
"imgui-1.81-1-wrap.zip::https://wrapdb.mesonbuild.com/v1/projects/imgui/1.81/1/get_zip"
"spdlog-1.8.5.tar.gz::https://github.com/gabime/spdlog/archive/v1.8.5.tar.gz"
"spdlog-1.8.5-1-wrap.zip::https://wrapdb.mesonbuild.com/v1/projects/spdlog/1.8.5/1/get_zip"
"nlohmann_json-3.10.5.zip::https://github.com/nlohmann/json/releases/download/v3.10.5/include.zip"
"vulkan-headers-1.2.158.tar.gz::https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.2.158.tar.gz"
"vulkan-headers-1.2.158-2-wrap.zip::https://wrapdb.mesonbuild.com/v2/vulkan-headers_1.2.158-2/get_patch"
"implot-0.16.zip::https://github.com/epezent/implot/archive/refs/tags/v0.16.zip"
"implot_0.16-1_patch.zip::https://wrapdb.mesonbuild.com/v2/implot_0.16-1/get_patch"
)
sha256sums=(
'SKIP'
'SKIP'
'1acc27a778b71d859878121a3f7b287cd81c29d720893d2b2bf74455bf9d52d6'
'9b21290c597d76bf8d4eeb3f9ffa024b11d9ea6c61e91d648ccc90b42843d584'
'1586508029a7d0670dfcb2d97575dcdc242d3868a259742b69f100801ab4e16b'
'ae878e732330ea1048f90d7e117c40c0cd2a6fb8ae5492c7955818ce3aaade6c'
'f7c619e03a06c0f25e8f47262dbc32d61fd033d2c91796812bf0f8c94fca78fb'
'6d00b442690b6a5c5d8f898311daafbce16d370cf64f53294c3b8c5c661e435f'
'944d0bd7c763ac721398dca2bb0f3b5ed16f67cef36810ede5061f35a543b4b8'
'3c38f275d5792b1286391102594329e98b17737924b344f98312ab09929b74be'
'b94997df68856753b72f0d7a3703b7d484d4745c567f3584ef97c96c25a5798e'
"53361271cfe274df8782e1e47bdc9e61b7af432ba30acbfe31723f9df2c257f3"
"860358cf5e73f458cd1e88f8c38116d123ab421d5ce2e4129ec38eaedd820e17"
"24f772c688f6b8a6e19d7efc10e4923a04a915f13d487b08b83553aa62ae1708"
"1c6b1462066a5452fa50c1da1dd47fed841f28232972c82d778f2962936568c7"
)
_build_args="-Dappend_libdir_mangohud=false -Dwith_xnvctrl=disabled -Dmangoapp_layer=true -Dtests=disabled"
@ -52,15 +47,14 @@ prepare() {
git -c protocol.file.allow=always submodule update
# meson subprojects
ln -sv "$srcdir/imgui-1.89.9" subprojects
ln -sv "$srcdir/spdlog-1.14.1" subprojects
ln -sv "$srcdir/imgui-1.81" subprojects
ln -sv "$srcdir/spdlog-1.8.5" subprojects
mkdir subprojects/nlohmann_json-3.10.5
ln -sv "$srcdir/include" subprojects/nlohmann_json-3.10.5/
ln -sv "$srcdir/single_include" subprojects/nlohmann_json-3.10.5/
ln -sv "$srcdir/LICENSE.MIT" subprojects/nlohmann_json-3.10.5/
ln -sv "$srcdir/meson.build" subprojects/nlohmann_json-3.10.5/
ln -sv "$srcdir/Vulkan-Headers-1.2.158" subprojects
ln -sv "$srcdir/implot-0.16" subprojects
}
build() {

@ -17,17 +17,14 @@ std::mutex amdgpu_common_metrics_m;
std::mutex amdgpu_m;
std::condition_variable amdgpu_c;
bool amdgpu_run_thread = true;
std::unique_ptr<Throttling> throttling;
bool amdgpu_verify_metrics(const std::string& path)
{
metrics_table_header header {};
FILE *f;
f = fopen(path.c_str(), "rb");
if (!f) {
SPDLOG_DEBUG("Failed to read the metrics header of '{}'", path);
if (!f)
return false;
}
if (fread(&header, sizeof(header), 1, f) == 0)
{
@ -42,8 +39,8 @@ bool amdgpu_verify_metrics(const std::string& path)
break;
cpuStats.cpu_type = "GPU";
return true;
case 2: // v2_1, v2_2, v2_3, v2_4
if(header.content_revision<=0 || header.content_revision>4)// v2_0, not naturally aligned
case 2: // v2_1, v2_2, v2_3
if(header.content_revision<=0 || header.content_revision>3)// v2_0, not naturally aligned
break;
cpuStats.cpu_type = "APU";
return true;
@ -55,10 +52,11 @@ bool amdgpu_verify_metrics(const std::string& path)
return false;
}
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define IS_VALID_METRIC(FIELD) (FIELD != 0xffff)
void amdgpu_get_instant_metrics(struct amdgpu_common_metrics *metrics) {
FILE *f;
void *buf[MAX(sizeof(struct gpu_metrics_v1_3), sizeof(struct gpu_metrics_v2_4))/sizeof(void*)+1];
void *buf[MAX(sizeof(struct gpu_metrics_v1_3), sizeof(struct gpu_metrics_v2_3))/sizeof(void*)+1];
struct metrics_table_header* header = (metrics_table_header*)buf;
f = fopen(metrics_path.c_str(), "rb");
@ -185,8 +183,6 @@ void amdgpu_get_instant_metrics(struct amdgpu_common_metrics *metrics) {
metrics->is_current_throttled = ((indep_throttle_status >> 16) & 0xFF) != 0;
metrics->is_temp_throttled = ((indep_throttle_status >> 32) & 0xFFFF) != 0;
metrics->is_other_throttled = ((indep_throttle_status >> 56) & 0xFF) != 0;
if (throttling)
throttling->indep_throttle_status = indep_throttle_status;
}
void amdgpu_get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT], bool &gpu_load_needs_dividing) {
@ -252,7 +248,7 @@ void amdgpu_metrics_polling_thread() {
}
}
void amdgpu_get_metrics(uint32_t deviceID){
void amdgpu_get_metrics(){
static bool init = false;
if (!init){
std::thread(amdgpu_metrics_polling_thread).detach();
@ -266,12 +262,7 @@ void amdgpu_get_metrics(uint32_t deviceID){
gpu_info.MemClock = amdgpu_common_metrics.current_uclk_mhz;
// Use hwmon instead, see gpu.cpp
if ( deviceID == 0x1435 || deviceID == 0x163f )
{
// If we are on VANGOGH (Steam Deck), then
// always use use core clock from GPU metrics.
gpu_info.CoreClock = amdgpu_common_metrics.current_gfxclk_mhz;
}
// gpu_info.CoreClock = amdgpu_common_metrics.current_gfxclk_mhz;
// gpu_info.temp = amdgpu_common_metrics.gpu_temp_c;
gpu_info.apu_cpu_power = amdgpu_common_metrics.average_cpu_power_w;
gpu_info.apu_cpu_temp = amdgpu_common_metrics.apu_cpu_temp_c;

@ -8,9 +8,7 @@
#include "overlay_params.h"
#include <mutex>
#include <condition_variable>
#include <vector>
#include <sys/param.h>
#include <algorithm>
// #include <vector>
#define METRICS_UPDATE_PERIOD_MS 500
#define METRICS_POLLING_PERIOD_MS 25
@ -21,9 +19,6 @@
#define UPDATE_METRIC_AVERAGE_FLOAT(FIELD) do { float value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } amdgpu_common_metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0)
#define UPDATE_METRIC_MAX(FIELD) do { int cur_max = metrics_buffer[0].FIELD; for (size_t s=1; s < METRICS_SAMPLE_COUNT; s++) { cur_max = MAX(cur_max, metrics_buffer[s].FIELD); }; amdgpu_common_metrics.FIELD = cur_max; } while(0)
#define UPDATE_METRIC_LAST(FIELD) do { amdgpu_common_metrics.FIELD = metrics_buffer[METRICS_SAMPLE_COUNT - 1].FIELD; } while(0)
#ifdef _WIN32
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
struct metrics_table_header {
uint16_t structure_size;
@ -162,76 +157,6 @@ struct gpu_metrics_v2_3 {
uint16_t average_temperature_l3[2];
};
struct gpu_metrics_v2_4 {
struct metrics_table_header common_header;
/* Temperature (unit: centi-Celsius) */
uint16_t temperature_gfx;
uint16_t temperature_soc;
uint16_t temperature_core[8];
uint16_t temperature_l3[2];
/* Utilization (unit: centi) */
uint16_t average_gfx_activity;
uint16_t average_mm_activity;
/* Driver attached timestamp (in ns) */
uint64_t system_clock_counter;
/* Power/Energy (unit: mW) */
uint16_t average_socket_power;
uint16_t average_cpu_power;
uint16_t average_soc_power;
uint16_t average_gfx_power;
uint16_t average_core_power[8];
/* Average clocks (unit: MHz) */
uint16_t average_gfxclk_frequency;
uint16_t average_socclk_frequency;
uint16_t average_uclk_frequency;
uint16_t average_fclk_frequency;
uint16_t average_vclk_frequency;
uint16_t average_dclk_frequency;
/* Current clocks (unit: MHz) */
uint16_t current_gfxclk;
uint16_t current_socclk;
uint16_t current_uclk;
uint16_t current_fclk;
uint16_t current_vclk;
uint16_t current_dclk;
uint16_t current_coreclk[8];
uint16_t current_l3clk[2];
/* Throttle status (ASIC dependent) */
uint32_t throttle_status;
/* Fans */
uint16_t fan_pwm;
uint16_t padding[3];
/* Throttle status (ASIC independent) */
uint64_t indep_throttle_status;
/* Average Temperature (unit: centi-Celsius) */
uint16_t average_temperature_gfx;
uint16_t average_temperature_soc;
uint16_t average_temperature_core[8];
uint16_t average_temperature_l3[2];
/* Power/Voltage (unit: mV) */
uint16_t average_cpu_voltage;
uint16_t average_soc_voltage;
uint16_t average_gfx_voltage;
/* Power/Current (unit: mA) */
uint16_t average_cpu_current;
uint16_t average_soc_current;
uint16_t average_gfx_current;
};
/* This structure is used to communicate the latest values of the amdgpu metrics.
* The direction of communication is amdgpu_polling_thread -> amdgpu_get_metrics().
*/
@ -263,48 +188,10 @@ struct amdgpu_common_metrics {
};
bool amdgpu_verify_metrics(const std::string& path);
void amdgpu_get_metrics(uint32_t deviceID);
void amdgpu_get_metrics();
extern std::string metrics_path;
extern std::condition_variable amdgpu_c;
extern bool amdgpu_run_thread;
void amdgpu_get_instant_metrics(struct amdgpu_common_metrics *metrics);
void amdgpu_metrics_polling_thread();
void amdgpu_get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT], bool &gpu_load_needs_dividing);
void amdgpu_trottling_thread(std::vector<float> &power, std::vector<float> &thermal);
class Throttling {
public:
std::vector<float> power;
std::vector<float> thermal;
int64_t indep_throttle_status;
Throttling()
: power(200, 0.0f),
thermal(200, 0.0f) {}
void update(){
if (((indep_throttle_status >> 0) & 0xFF) != 0)
power.push_back(0.1);
else
power.push_back(0);
if (((indep_throttle_status >> 32) & 0xFFFF) != 0)
thermal.push_back(0.1);
else
thermal.push_back(0);
power.erase(power.begin());
thermal.erase(thermal.begin());
}
bool power_throttling(){
return std::find(power.begin(), power.end(), 0.1f) != power.end();
}
bool thermal_throttling(){
return std::find(thermal.begin(), thermal.end(), 0.1f) != thermal.end();
}
};
extern std::unique_ptr<Throttling> throttling;

@ -19,9 +19,6 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "amdgpu.h"
#ifdef __linux__
#include "implot.h"
#endif
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
@ -51,7 +48,7 @@ static uint32_t screenWidth, screenHeight;
static unsigned int get_prop(const char* propName){
Display *x11_display = glfwGetX11Display();
Atom gamescope_focused = XInternAtom(x11_display, propName, false);
Atom gamescope_focused = XInternAtom(x11_display, propName, true);
auto scr = DefaultScreen(x11_display);
auto root = RootWindow(x11_display, scr);
Atom actual;
@ -73,7 +70,7 @@ static unsigned int get_prop(const char* propName){
}
return i;
}
return -1;
return 0;
}
static void ctrl_thread(){
@ -133,13 +130,10 @@ static void ctrl_thread(){
bool new_frame = false;
static void gamescope_frametime(uint64_t app_frametime_ns, uint64_t latency_ns){
if (app_frametime_ns != uint64_t(-1))
{
float app_frametime_ms = app_frametime_ns / 1000000.f;
HUDElements.gamescope_debug_app.push_back(app_frametime_ms);
if (HUDElements.gamescope_debug_app.size() > 200)
HUDElements.gamescope_debug_app.erase(HUDElements.gamescope_debug_app.begin());
}
float app_frametime_ms = app_frametime_ns / 1000000.f;
HUDElements.gamescope_debug_app.push_back(app_frametime_ms);
if (HUDElements.gamescope_debug_app.size() > 200)
HUDElements.gamescope_debug_app.erase(HUDElements.gamescope_debug_app.begin());
float latency_ms = latency_ns / 1000000.f;
if (latency_ns == uint64_t(-1))
@ -162,63 +156,50 @@ static void msg_read_thread(){
while (1){
// make sure that the message recieved is compatible
// and that we're not trying to use variables that don't exist (yet)
size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0);
if (msg_size != -1)
{
if (hdr->version == 1){
if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){
bool should_new_frame = false;
if (mangoapp_v1->visible_frametime_ns != ~(0lu) && (!params.no_display || logger->is_active())) {
update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns);
should_new_frame = true;
}
if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){
HUDElements.g_fsrUpscale = mangoapp_v1->fsrUpscale;
if (params.fsr_steam_sharpness < 0)
HUDElements.g_fsrSharpness = mangoapp_v1->fsrSharpness;
else
HUDElements.g_fsrSharpness = params.fsr_steam_sharpness - mangoapp_v1->fsrSharpness;
}
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam]){
steam_focused = get_prop("GAMESCOPE_FOCUSED_APP_GFX") == 769;
} else {
steam_focused = false;
}
// if (!steam_focused && mangoapp_v1->pid != previous_pid){
// string path = "/tmp/mangoapp/" + to_string(mangoapp_v1->pid) + ".json";
// ifstream i(path);
// if (i.fail()){
// sw_stats.engine = EngineTypes::GAMESCOPE;
// } else {
// json j;
// i >> j;
// sw_stats.engine = static_cast<EngineTypes> (j["engine"]);
// }
// previous_pid = mangoapp_v1->pid;
// }
if (msg_size > offsetof(mangoapp_msg_v1, latency_ns))
gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns);
if (should_new_frame)
{
{
std::unique_lock<std::mutex> lk(mangoapp_m);
new_frame = true;
}
mangoapp_cv.notify_one();
screenWidth = mangoapp_v1->outputWidth;
screenHeight = mangoapp_v1->outputHeight;
}
size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0) + sizeof(long);
if (hdr->version == 1){
if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){
if (!params.no_display || logger->is_active())
update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns);
if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){
HUDElements.g_fsrUpscale = mangoapp_v1->fsrUpscale;
if (params.fsr_steam_sharpness < 0)
HUDElements.g_fsrSharpness = mangoapp_v1->fsrSharpness;
else
HUDElements.g_fsrSharpness = params.fsr_steam_sharpness - mangoapp_v1->fsrSharpness;
}
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam]){
steam_focused = get_prop("GAMESCOPE_FOCUSED_APP_GFX") == 769;
} else {
steam_focused = false;
}
// if (!steam_focused && mangoapp_v1->pid != previous_pid){
// string path = "/tmp/mangoapp/" + to_string(mangoapp_v1->pid) + ".json";
// ifstream i(path);
// if (i.fail()){
// sw_stats.engine = EngineTypes::GAMESCOPE;
// } else {
// json j;
// i >> j;
// sw_stats.engine = static_cast<EngineTypes> (j["engine"]);
// }
// previous_pid = mangoapp_v1->pid;
// }
if (msg_size > offsetof(mangoapp_msg_v1, latency_ns))
gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns);
{
std::unique_lock<std::mutex> lk(mangoapp_m);
new_frame = true;
}
} else {
printf("Unsupported mangoapp struct version: %i\n", hdr->version);
exit(1);
mangoapp_cv.notify_one();
screenWidth = mangoapp_v1->outputWidth;
screenHeight = mangoapp_v1->outputHeight;
}
}
else
{
printf("mangoapp: msgrcv returned -1 with error %d - %s\n", errno, strerror(errno));
} else {
printf("Unsupported mangoapp struct version: %i\n", hdr->version);
exit(1);
}
}
}
@ -226,7 +207,6 @@ static void msg_read_thread(){
static const char *GamescopeOverlayProperty = "GAMESCOPE_EXTERNAL_OVERLAY";
static GLFWwindow* init(const char* glsl_version){
init_spdlog();
GLFWwindow *window = glfwCreateWindow(1280, 800, "mangoapp overlay window", NULL, NULL);
Display *x11_display = glfwGetX11Display();
Window x11_window = glfwGetX11Window(window);
@ -241,9 +221,6 @@ static GLFWwindow* init(const char* glsl_version){
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
ImGui::CreateContext();
#ifdef __linux__
ImPlot::CreateContext();
#endif
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.IniFilename = NULL;
ImGui::StyleColorsDark();
@ -259,11 +236,6 @@ static void shutdown(GLFWwindow* window){
glfwDestroyWindow(window);
}
static void get_atom_info(){
HUDElements.hdr_status = get_prop("GAMESCOPE_COLOR_APP_WANTS_HDR_FEEDBACK");
HUDElements.refresh = get_prop("GAMESCOPE_DISPLAY_REFRESH_RATE_FEEDBACK");
}
static bool render(GLFWwindow* window) {
if (HUDElements.colors.update)
HUDElements.convert_colors(params);
@ -275,7 +247,6 @@ static bool render(GLFWwindow* window) {
overlay_new_frame(params);
position_layer(sw_stats, params, window_size);
render_imgui(sw_stats, params, window_size, true);
get_atom_info();
overlay_end_frame();
if (screenWidth && screenHeight)
glfwSetWindowSize(window, screenWidth, screenHeight);
@ -339,18 +310,12 @@ int main(int, char**)
vendorID = 0x10de;
}
}
HUDElements.vendorID = vendorID;
init_gpu_stats(vendorID, 0, params);
init_system_info();
sw_stats.engine = EngineTypes::GAMESCOPE;
std::thread(msg_read_thread).detach();
std::thread(ctrl_thread).detach();
if(!logger) logger = std::make_unique<Logger>(HUDElements.params);
Atom noFocusAtom = XInternAtom(x11_display, "GAMESCOPE_NO_FOCUS", False);
uint32_t value = 1;
XChangeProperty(x11_display, x11_window, noFocusAtom, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&value, 1);
// Main loop
while (!glfwWindowShouldClose(window)){
if (!params.no_display){

@ -25,7 +25,6 @@ static std::vector<std::string> blacklist {
"EpicGamesLauncher.exe",
"IGOProxy.exe",
"IGOProxy64.exe",
"monado-service",
"Origin.exe",
"OriginThinSetupInternal.exe",
"steam",
@ -50,14 +49,11 @@ static std::vector<std::string> blacklist {
"RSI Launcher.exe",
"tabtip.exe",
"steam.exe",
"wine64-preloader",
"explorer.exe",
"wine-preloader",
"iexplore.exe",
"rundll32.exe",
"Launcher", //Paradox Interactive Launcher
"steamwebhelper.exe",
"EpicWebHelper.exe",
"UplayWebCore.exe"
};

@ -99,6 +99,8 @@ static void enumerate_config_files(std::vector<std::string>& paths) {
}
void parseConfigFile(overlay_params& params) {
HUDElements.options.clear();
params.options.clear();
std::vector<std::string> paths;
const char *cfg_file = getenv("MANGOHUD_CONFIGFILE");

@ -469,8 +469,7 @@ static bool find_input(const std::string& path, const char* input_prefix, std::s
if (uscore != std::string::npos) {
file.erase(uscore, std::string::npos);
input = path + "/" + file + "_input";
//9 characters should not overflow the 32-bit int
return std::stoi(read_line(input).substr(0, 9)) > 0;
return true;
}
}
return false;
@ -520,14 +519,6 @@ bool CPUStats::GetCpuFile() {
} else if (name == "it8603") {
find_input(path, "temp", input, "temp1");
break;
} else if (starts_with(name, "nct")) {
// Only break if nct module has TSI0_TEMP node
if (find_input(path, "temp", input, "TSI0_TEMP"))
break;
} else if (name == "asusec") {
find_input(path, "temp", input, "CPU");
break;
} else {
path.clear();
}

@ -56,7 +56,6 @@ enum {
};
struct CPUPowerData {
virtual ~CPUPowerData() = default;
int source;
};

@ -1,225 +0,0 @@
#include "device.h"
#include <filesystem.h>
#include <iostream>
#include <algorithm>
#include <spdlog/spdlog.h>
namespace fs = ghc::filesystem;
using namespace std;
std::mutex device_lock;
std::vector<device_batt> device_data;
std::vector<std::string> list;
bool device_found = false;
bool check_gamepad = false;
bool check_mouse = false;
int device_count = 0;
int xbox_count = 0;
int ds4_count = 0;
int ds5_count = 0;
int switch_count = 0;
int bitdo_count = 0;
int logi_count = 0; //Logitech devices, mice & keyboards etc.
int shield_count = 0;
std::string xbox_paths [2]{"gip","xpadneo"};
static bool operator<(const device_batt& a, const device_batt& b)
{
return a.name < b.name;
}
void device_update(const struct overlay_params& params){
std::unique_lock<std::mutex> l(device_lock);
fs::path path("/sys/class/power_supply");
list.clear();
xbox_count = 0;
ds4_count = 0;
ds5_count = 0;
switch_count = 0;
bitdo_count = 0;
shield_count = 0;
for (auto &p : fs::directory_iterator(path)) {
string fileName = p.path().filename();
//Gamepads
if (std::find(params.device_battery.begin(), params.device_battery.end(), "gamepad") != params.device_battery.end()){
check_gamepad = true;
//CHECK XONE AND XPADNEO DEVICES
for (string n : xbox_paths ) {
if (fileName.find(n) != std::string::npos) {
list.push_back(p.path());
device_found = true;
xbox_count += 1;
}
}
//CHECK FOR DUAL SHOCK 4 DEVICES
if (fileName.find("sony_controller") != std::string::npos) {
list.push_back(p.path());
device_found = true;
ds4_count +=1 ;
}
if (fileName.find("ps-controller") != std::string::npos) {
list.push_back(p.path());
device_found = true;
ds5_count +=1 ;
}
//CHECK FOR NINTENDO SWITCH DEVICES
if (fileName.find("nintendo_switch_controller") != std::string::npos) {
list.push_back(p.path());
device_found = true;
switch_count += 1;
}
//CHECK * BITDO DEVICES
if (fileName.find("hid-e4") != std::string::npos) {
list.push_back(p.path());
device_found = true;
bitdo_count += 1;
}
//CHECK NVIDIA SHIELD DEVICES
if (fileName.find("thunderstrike") != std::string::npos) {
list.push_back(p.path());
device_found = true;
shield_count += 1;
}
}
// Mice and Keyboards
//CHECK LOGITECH DEVICES
if (std::find(params.device_battery.begin(), params.device_battery.end(), "mouse") != params.device_battery.end()) {
check_mouse = true;
if (fileName.find("hidpp_battery") != std::string::npos) {
list.push_back(p.path());
device_found = true;
}
}
}
}
void device_info () {
std::unique_lock<std::mutex> l(device_lock);
device_count = 0;
device_data.clear();
//gamepad counters
int xbox_counter = 0;
int ds4_counter = 0;
int ds5_counter = 0;
int switch_counter = 0;
int bitdo_counter = 0;
int shield_counter = 0;
for (auto &path : list ) {
//Set devices paths
std::string capacity = path + "/capacity";
std::string capacity_level = path + "/capacity_level";
std::string status = path + "/status";
std::string model = path + "/model_name";
std::ifstream input_capacity(capacity);
std::ifstream input_capacity_level(capacity_level);
std::ifstream input_status(status);
std::ifstream device_name(model);
std::string line;
device_data.push_back(device_batt());
// GAMEPADS
//Xone and xpadneo devices
if (check_gamepad == true) {
if (path.find("gip") != std::string::npos || path.find("xpadneo") != std::string::npos) {
if (xbox_count == 1 )
device_data[device_count].name = "XBOX PAD";
else
device_data[device_count].name = "XBOX PAD-" + to_string(xbox_counter + 1);
xbox_counter++;
}
//DualShock 4 devices
if (path.find("sony_controller") != std::string::npos) {
if (ds4_count == 1)
device_data[device_count].name = "DS4 PAD";
else
device_data[device_count].name = "DS4 PAD-" + to_string(ds4_counter + 1);
ds4_counter++;
}
//DualSense 5 devices
//Dual Shock 4 added to hid-playstation in Linux 6.2
if (path.find("ps-controller") != std::string::npos) {
if (ds5_count == 1)
device_data[device_count].name = "DS4/5 PAD";
else
device_data[device_count].name = "DS4/5 PAD-" + to_string(ds5_counter + 1);
ds5_counter++;
}
//Nintendo Switch devices
if (path.find("nintendo_switch_controller") != std::string::npos) {
if (switch_count == 1)
device_data[device_count].name = "SWITCH PAD";
else
device_data[device_count].name = "SWITCH PAD-" + to_string(switch_counter + 1);
switch_counter++;
}
//8bitdo devices
if (path.find("hid-e4") != std::string::npos) {
if (bitdo_count == 1)
device_data[device_count].name = "8BITDO PAD";
else
device_data[device_count].name = "8BITDO PAD-" + to_string(bitdo_counter + 1);
bitdo_counter++;
}
//Shield devices
if (path.find("thunderstrike") != std::string::npos) {
if (shield_count == 1)
device_data[device_count].name = "SHIELD PAD";
else
device_data[device_count].name = "SHIELD PAD-" + to_string(shield_counter + 1);
shield_counter++;
}
}
// MICE AND KEYBOARDS
//Logitech Devices
if (check_mouse == true) {
if (path.find("hidpp_battery") != std::string::npos) {
// Find a good way truncate name or retreive device type before using this
// if (std::getline(device_name, line)) {
// device_data[device_count].name = line;
// }
device_data[device_count].name = "LOGI MOUSE/KB";
}
}
//Get device charging status
if (std::getline(input_status, line)) {
if (line == "Charging" || line == "Full")
device_data[device_count].is_charging = true;
}
//Get device Battery
if (fs::exists(capacity)) {
if (std::getline(input_capacity, line)) {
device_data[device_count].battery_percent = line;
device_data[device_count].report_percent = true;
switch(std::stoi(line)) {
case 0 ... 25:
device_data[device_count].battery = "Low";
break;
case 26 ... 49:
device_data[device_count].battery = "Normal";
break;
case 50 ... 74:
device_data[device_count].battery = "High";
break;
case 75 ... 100:
device_data[device_count].battery = "Full";
break;
}
}
}
else {
if (std::getline(input_capacity_level, line)) {
device_data[device_count].battery = line;
}
}
std::sort(device_data.begin(), device_data.end());
device_count += 1;
}
}

@ -1,25 +0,0 @@
#pragma once
#ifndef MANGOHUD_DEVICE_H
#define MANGOHUD_DEVICE_H
#include <vector>
#include <string>
#include "overlay_params.h"
struct overlay_params;
struct device_batt {
std::string battery;
std::string name;
bool report_percent;
std::string battery_percent;
bool is_charging;
};
extern std::vector<device_batt> device_data;
extern std::mutex device_lock;
extern bool device_found;
extern int device_count;
void device_update(const overlay_params& params);
void device_info();
#endif // MANGOHUD_DEVICE_H

@ -29,12 +29,6 @@
* \{
*/
#ifdef __GLIBC__
# define ABS_ADDR(obj, ptr) (ptr)
#else
# define ABS_ADDR(obj, ptr) ((obj->addr) + (ptr))
#endif
struct eh_iterate_callback_args {
eh_iterate_obj_callback_func callback;
void *arg;
@ -202,22 +196,22 @@ int eh_init_obj(eh_obj_t *obj)
if (obj->strtab)
return ENOTSUP;
obj->strtab = (const char *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
obj->strtab = (const char *) obj->dynamic[p].d_un.d_ptr;
} else if (obj->dynamic[p].d_tag == DT_HASH) {
if (obj->hash)
return ENOTSUP;
obj->hash = (ElfW(Word) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
obj->hash = (ElfW(Word) *) obj->dynamic[p].d_un.d_ptr;
} else if (obj->dynamic[p].d_tag == DT_GNU_HASH) {
if (obj->gnu_hash)
return ENOTSUP;
obj->gnu_hash = (Elf32_Word *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
obj->gnu_hash = (Elf32_Word *) obj->dynamic[p].d_un.d_ptr;
} else if (obj->dynamic[p].d_tag == DT_SYMTAB) {
if (obj->symtab)
return ENOTSUP;
obj->symtab = (ElfW(Sym) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
obj->symtab = (ElfW(Sym) *) obj->dynamic[p].d_un.d_ptr;
}
p++;
}
@ -455,7 +449,7 @@ int eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next)
int eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val)
{
ElfW(Rela) *rela = (ElfW(Rela) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
ElfW(Rela) *rela = (ElfW(Rela) *) obj->dynamic[p].d_un.d_ptr;
ElfW(Dyn) *relasize;
unsigned int i;
@ -476,7 +470,7 @@ int eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val)
int eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val)
{
ElfW(Rel) *rel = (ElfW(Rel) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
ElfW(Rel) *rel = (ElfW(Rel) *) obj->dynamic[p].d_un.d_ptr;
ElfW(Dyn) *relsize;
unsigned int i;
@ -526,7 +520,7 @@ int eh_set_rel(eh_obj_t *obj, const char *sym, void *val)
int eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg)
{
ElfW(Rela) *rela = (ElfW(Rela) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
ElfW(Rela) *rela = (ElfW(Rela) *) obj->dynamic[p].d_un.d_ptr;
ElfW(Dyn) *relasize;
eh_rel_t rel;
eh_sym_t sym;
@ -556,7 +550,7 @@ int eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callb
int eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg)
{
ElfW(Rel) *relp = (ElfW(Rel) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);
ElfW(Rel) *relp = (ElfW(Rel) *) obj->dynamic[p].d_un.d_ptr;
ElfW(Dyn) *relsize;
eh_rel_t rel;
eh_sym_t sym;

@ -201,10 +201,4 @@ bool lib_loaded(const std::string& lib) {
}
std::string remove_parentheses(const std::string& text) {
// Remove parentheses and text between them
std::regex pattern("\\([^)]*\\)");
return std::regex_replace(text, pattern, "");
}
#endif // __linux__

@ -4,7 +4,7 @@
#include <string>
#include <vector>
#include <regex>
enum LS_FLAGS
{
LS_DIRS = 0x01,
@ -24,6 +24,5 @@ std::string get_home_dir();
std::string get_data_dir();
std::string get_config_dir();
bool lib_loaded(const std::string& lib);
std::string remove_parentheses(const std::string&);
#endif //MANGOHUD_FILE_UTILS_H

@ -32,9 +32,6 @@ void create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*
// Load Icon file and merge to exisitng font
ImFontConfig config;
config.MergeMode = true;
// ImGui changed OversampleH default to 2, but it appears to sometimes cause
// crashing issues in 32bit applications.
config.OversampleH = 3;
static const ImWchar icon_ranges[] = { ICON_MIN_FK, ICON_MAX_FK, 0 };
ImVector<ImWchar> glyph_ranges;

@ -1,165 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <thread>
#include <mesa/util/os_time.h>
#include <numeric>
#include <mutex>
#include <algorithm>
#include <condition_variable>
#include <stdexcept>
#include <iomanip>
#include <spdlog/spdlog.h>
struct metric_t {
std::string name;
float value;
std::string display_name;
};
class fpsMetrics {
private:
std::vector<std::pair<uint64_t, float>> fps_stats;
std::thread thread;
std::mutex mtx;
std::condition_variable cv;
bool run = false;
bool thread_init = false;
bool terminate = false;
bool resetting = false;
void calculate(){
thread_init = true;
while (true){
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this] { return run; });
if (terminate)
break;
std::vector<float> sorted_values;
for (const auto& p : fps_stats)
sorted_values.push_back(p.second);
std::sort(sorted_values.begin(), sorted_values.end());
auto it = metrics.begin();
while (it != metrics.end()) {
if (it->name == "AVG") {
it->display_name = it->name;
if (!fps_stats.empty()) {
float sum = std::accumulate(fps_stats.begin(), fps_stats.end(), 0.0f,
[](float acc, const std::pair<uint64_t, float>& p) {
return acc + p.second;
});
it->value = sum / fps_stats.size();
++it;
}
} else {
try {
float val = std::stof(it->name);
if (val <= 0 || val >= 1 ) {
SPDLOG_DEBUG("Failed to use fps metric, it's out of range {}", it->name);
it = metrics.erase(it);
break;
}
float multiplied_val = val * 100;
std::ostringstream stream;
if (multiplied_val == static_cast<int>(multiplied_val)) {
stream << std::fixed << std::setprecision(0) << multiplied_val << "%";
} else {
stream << std::fixed << std::setprecision(1) << multiplied_val << "%";
}
it->display_name = stream.str();
uint64_t idx = val * sorted_values.size() - 1;
if (idx >= sorted_values.size())
break;
it->value = sorted_values[idx];
++it;
} catch (const std::invalid_argument& e) {
SPDLOG_DEBUG("Failed to use fps metric value {}", it->name);
it = metrics.erase(it);
}
}
}
run = false;
}
}
public:
std::vector<metric_t> metrics;
fpsMetrics(std::vector<std::string> values){
// capitalize string
for (auto& val : values){
for(char& c : val) {
c = std::toupper(static_cast<unsigned char>(c));
}
metrics.push_back({val, 0.0f});
}
if (!thread_init){
thread = std::thread(&fpsMetrics::calculate, this);
}
};
void update(uint64_t now, double fps){
if (resetting)
return;
if (fps > 0.0001)
fps_stats.push_back({now, fps});
uint64_t ten_minute_duration = 600000000000ULL; // 10 minutes in nanoseconds
// Check if the system's uptime is less than 10 minutes
if (now >= ten_minute_duration) {
uint64_t ten_minutes_ago = now - ten_minute_duration;
fps_stats.erase(
std::remove_if(
fps_stats.begin(),
fps_stats.end(),
[ten_minutes_ago](const std::pair<uint64_t, float>& entry) {
return entry.first < ten_minutes_ago;
}
),
fps_stats.end()
);
}
}
void update_thread(){
if (resetting)
return;
{
std::lock_guard<std::mutex> lock(mtx);
run = true;
}
cv.notify_one();
}
void reset_metrics(){
resetting = true;
while (run){}
fps_stats.clear();
resetting = false;
}
~fpsMetrics(){
terminate = true;
{
std::lock_guard<std::mutex> lock(mtx);
run = true;
}
cv.notify_one();
thread.join();
}
};
extern std::unique_ptr<fpsMetrics> fpsmetrics;

@ -0,0 +1,186 @@
#include "gamepad.h"
#include <filesystem.h>
#include <iostream>
#include <algorithm>
#include <spdlog/spdlog.h>
namespace fs = ghc::filesystem;
using namespace std;
std::vector<gamepad> gamepad_data;
std::vector<std::string> list;
bool gamepad_found = false;
int gamepad_count = 0;
int xbox_count = 0;
int ds4_count = 0;
int ds5_count = 0;
int switch_count = 0;
int bitdo_count = 0;
int logi_count = 0; //Logitech devices, mice & keyboards etc.
std::string xbox_paths [2]{"gip","xpadneo"};
static bool operator<(const gamepad& a, const gamepad& b)
{
return a.name < b.name;
}
void gamepad_update(){
fs::path path("/sys/class/power_supply");
list.clear();
xbox_count = 0;
ds4_count = 0;
ds5_count = 0;
switch_count = 0;
bitdo_count = 0;
for (auto &p : fs::directory_iterator(path)) {
string fileName = p.path().filename();
//Gamepads
//CHECK XONE AND XPADNEO DEVICES
for (string n : xbox_paths ) {
if (fileName.find(n) != std::string::npos) {
list.push_back(p.path());
gamepad_found = true;
xbox_count += 1;
}
}
//CHECK FOR DUAL SHOCK 4 DEVICES
if (fileName.find("sony_controller") != std::string::npos) {
list.push_back(p.path());
gamepad_found = true;
ds4_count +=1 ;
}
if (fileName.find("ps-controller") != std::string::npos) {
list.push_back(p.path());
gamepad_found = true;
ds5_count +=1 ;
}
//CHECK FOR NINTENDO SWITCH DEVICES
if (fileName.find("nintendo_switch_controller") != std::string::npos) {
list.push_back(p.path());
gamepad_found = true;
switch_count += 1;
}
//CHECK * BITDO DEVICES
if (fileName.find("hid-e4") != std::string::npos) {
list.push_back(p.path());
gamepad_found = true;
bitdo_count += 1;
}
// Mice and Keyboards
//CHECK LOGITECH DEVICES
if (fileName.find("hidpp_battery") != std::string::npos) {
list.push_back(p.path());
gamepad_found = true;
}
}
}
void gamepad_info () {
gamepad_count = 0;
gamepad_data.clear();
//gamepad counters
int xbox_counter = 0;
int ds4_counter = 0;
int ds5_counter = 0;
int switch_counter = 0;
int bitdo_counter = 0;
for (auto &path : list ) {
//Set devices paths
std::string capacity = path + "/capacity";
std::string capacity_level = path + "/capacity_level";
std::string status = path + "/status";
std::string model = path + "/model_name";
std::ifstream input_capacity(capacity);
std::ifstream input_capacity_level(capacity_level);
std::ifstream input_status(status);
std::ifstream device_name(model);
std::string line;
gamepad_data.push_back(gamepad());
//Xone and xpadneo devices
if (path.find("gip") != std::string::npos || path.find("xpadneo") != std::string::npos) {
if (xbox_count == 1 )
gamepad_data[gamepad_count].name = "XBOX PAD";
else
gamepad_data[gamepad_count].name = "XBOX PAD-" + to_string(xbox_counter + 1);
xbox_counter++;
}
//DualShock 4 devices
if (path.find("sony_controller") != std::string::npos) {
if (ds4_count == 1)
gamepad_data[gamepad_count].name = "DS4 PAD";
else
gamepad_data[gamepad_count].name = "DS4 PAD-" + to_string(ds4_counter + 1);
ds4_counter++;
}
//DualSense 5 devices
//Dual Shock 4 added to hid-playstation in Linux 6.2
if (path.find("ps-controller") != std::string::npos) {
if (ds5_count == 1)
gamepad_data[gamepad_count].name = "DS4/5 PAD";
else
gamepad_data[gamepad_count].name = "DS4/5 PAD-" + to_string(ds5_counter + 1);
ds5_counter++;
}
//Nintendo Switch devices
if (path.find("nintendo_switch_controller") != std::string::npos) {
if (switch_count == 1)
gamepad_data[gamepad_count].name = "SWITCH PAD";
else
gamepad_data[gamepad_count].name = "SWITCH PAD-" + to_string(switch_counter + 1);
switch_counter++;
}
//8bitdo devices
if (path.find("hid-e4") != std::string::npos) {
if (bitdo_count == 1)
gamepad_data[gamepad_count].name = "8BITDO PAD";
else
gamepad_data[gamepad_count].name = "8BITDO PAD-" + to_string(bitdo_counter + 1);
bitdo_counter++;
}
//Logitech Devices
if (path.find("hidpp_battery") != std::string::npos) {
if (std::getline(device_name, line)) {
gamepad_data[gamepad_count].name = line;
}
}
//Get device charging status
if (std::getline(input_status, line)) {
if (line == "Charging" || line == "Full")
gamepad_data[gamepad_count].is_charging = true;
}
//Get device Battery
if (fs::exists(capacity)) {
if (std::getline(input_capacity, line)) {
gamepad_data[gamepad_count].battery_percent = line;
gamepad_data[gamepad_count].report_percent = true;
switch(std::stoi(line)) {
case 0 ... 25:
gamepad_data[gamepad_count].battery = "Low";
break;
case 26 ... 49:
gamepad_data[gamepad_count].battery = "Normal";
break;
case 50 ... 74:
gamepad_data[gamepad_count].battery = "High";
break;
case 75 ... 100:
gamepad_data[gamepad_count].battery = "Full";
break;
}
}
}
else {
if (std::getline(input_capacity_level, line)) {
gamepad_data[gamepad_count].battery = line;
}
}
std::sort(gamepad_data.begin(), gamepad_data.end());
gamepad_count += 1;
}
}

@ -0,0 +1,23 @@
#pragma once
#ifndef MANGOHUD_GAMEPAD_H
#define MANGOHUD_GAMEPAD_H
#include <vector>
#include <string>
struct gamepad {
std::string battery;
std::string name;
bool report_percent;
std::string battery_percent;
bool is_charging;
};
extern std::vector<gamepad> gamepad_data;
extern bool gamepad_found;
extern int gamepad_count;
void gamepad_update();
void gamepad_info();
#endif // MANGOHUD_GAMEPAD_H

@ -8,9 +8,6 @@
#include <unistd.h>
#include <spdlog/spdlog.h>
#include <imgui.h>
#ifdef __linux__
#include <implot.h>
#endif
#include "gl_hud.h"
#include "file_utils.h"
#include "notify.h"
@ -139,29 +136,22 @@ void imgui_create(void *ctx, const gl_wsi plat)
} else if (vendor.find("Intel") != std::string::npos
|| deviceName.find("Intel") != std::string::npos) {
vendorID = 0x8086;
} else if (vendor.find("freedreno") != std::string::npos) {
vendorID = 0x5143;
} else {
vendorID = 0x10de;
}
HUDElements.vendorID = vendorID;
uint32_t device_id = 0;
if (plat == gl_wsi::GL_WSI_GLX)
glx_mesa_queryInteger(GLX_RENDERER_DEVICE_ID_MESA, &device_id);
SPDLOG_DEBUG("GL device id: {:04X}", device_id);
init_gpu_stats(vendorID, device_id, params);
sw_stats.gpuName = gpu = remove_parentheses(deviceName);
sw_stats.gpuName = gpu = deviceName;
SPDLOG_DEBUG("gpu: {}", gpu);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGuiContext *saved_ctx = ImGui::GetCurrentContext();
state.imgui_ctx = ImGui::CreateContext();
#ifdef __linux__
ImPlot::CreateContext();
#endif
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls

@ -20,7 +20,7 @@ static void* get_egl_proc_address(const char* name) {
void *func = nullptr;
static void *(*pfn_eglGetProcAddress)(const char*) = nullptr;
if (!pfn_eglGetProcAddress) {
void *handle = real_dlopen("libEGL.so.1", RTLD_LAZY);
void *handle = real_dlopen("libEGL.so.1", RTLD_LAZY|RTLD_LOCAL);
if (!handle) {
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libEGL.so.1: {}", dlerror());
} else {
@ -35,7 +35,7 @@ static void* get_egl_proc_address(const char* name) {
func = get_proc_address( name );
if (!func) {
SPDLOG_ERROR("Failed to get function '{}'", name);
SPDLOG_DEBUG("Failed to get function '{}'", name);
}
return func;

@ -19,7 +19,6 @@
#include <glad/glad.h>
#include "gl_hud.h"
#include "../config.h"
using namespace MangoHud::GL;
@ -112,7 +111,7 @@ EXPORT_C_(int) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
if (!is_blacklisted()) {
if (ret) {
imgui_set_context(ctx, gl_wsi::GL_WSI_GLX);
SPDLOG_DEBUG("GL ref count: {}", refcnt.load());
SPDLOG_DEBUG("GL ref count: {}", refcnt);
}
// Afaik -1 only works with EXT version if it has GLX_EXT_swap_control_tear, maybe EGL_MESA_swap_control_tear someday
@ -305,7 +304,7 @@ EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name)
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
void *real_func = get_glx_proc_address((const char*)procName);
void *func = mangohud_find_glx_ptr( (const char*)procName );
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast<const char*>(procName), real_func, func);
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func)
return func;
@ -316,7 +315,7 @@ EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) {
void *real_func = get_glx_proc_address((const char*)procName);
void *func = mangohud_find_glx_ptr( (const char*)procName );
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast<const char*>(procName), real_func, func);
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func)
return func;

@ -46,7 +46,6 @@ void getNvidiaGpuInfo(const struct overlay_params& params){
gpu_info.CoreClock = nvidiaCoreClock;
gpu_info.MemClock = nvidiaMemClock;
gpu_info.powerUsage = nvidiaPowerUsage / 1000;
gpu_info.fan_rpm = false;
gpu_info.memoryTotal = nvidiaMemory.total / (1024.f * 1024.f * 1024.f);
gpu_info.fan_speed = nvidiaFanSpeed;
if (params.enabled[OVERLAY_PARAM_ENABLED_throttling_status]){
@ -56,10 +55,8 @@ void getNvidiaGpuInfo(const struct overlay_params& params){
}
#ifdef HAVE_XNVCTRL
static bool nvctrl_available = checkXNVCtrl();
if (nvctrl_available) {
gpu_info.fan_rpm = true;
if (nvctrl_available)
gpu_info.fan_speed = getNvctrlFanSpeed();
}
#endif
return;
@ -75,7 +72,6 @@ void getNvidiaGpuInfo(const struct overlay_params& params){
gpu_info.MemClock = nvctrl_info.MemClock;
gpu_info.powerUsage = 0;
gpu_info.memoryTotal = nvctrl_info.memoryTotal;
gpu_info.fan_rpm = true;
gpu_info.fan_speed = nvctrl_info.fan_speed;
return;
}
@ -98,6 +94,7 @@ void getAmdGpuInfo(){
gpu_info.load = value;
}
if (amdgpu.memory_clock) {
rewind(amdgpu.memory_clock);
fflush(amdgpu.memory_clock);
@ -107,9 +104,6 @@ void getAmdGpuInfo(){
gpu_info.MemClock = value / 1000000;
}
// TODO: on some gpus this will use the power1_input instead
// this value is instantaneous and should be averaged over time
// probably just average everything in this function to be safe
if (amdgpu.power_usage) {
rewind(amdgpu.power_usage);
fflush(amdgpu.power_usage);
@ -118,15 +112,14 @@ void getAmdGpuInfo(){
gpu_info.powerUsage = value / 1000000;
}
}
if (amdgpu.fan) {
rewind(amdgpu.fan);
fflush(amdgpu.fan);
if (fscanf(amdgpu.fan, "%" PRId64, &value) != 1)
value = 0;
gpu_info.fan_speed = value;
gpu_info.fan_rpm = true;
if (amdgpu.fan) {
rewind(amdgpu.fan);
fflush(amdgpu.fan);
if (fscanf(amdgpu.fan, "%" PRId64, &value) != 1)
value = 0;
gpu_info.fan_speed = value;
}
}
if (amdgpu.vram_total) {

@ -44,7 +44,6 @@ struct gpuInfo{
float gtt_used;
int fan_speed;
int voltage;
bool fan_rpm;
};
extern struct gpuInfo gpu_info;

@ -15,7 +15,6 @@ EXPORT_C_(void*) dlsym(void * handle, const char * name)
find_egl_ptr = reinterpret_cast<decltype(find_egl_ptr)> (real_dlsym(RTLD_NEXT, "mangohud_find_egl_ptr"));
void* func = nullptr;
bool is_angle = real_dlsym(handle, "eglStreamPostD3DTextureANGLE");
void* real_func = real_dlsym(handle, name);
if (find_glx_ptr && real_func) {
@ -26,7 +25,7 @@ EXPORT_C_(void*) dlsym(void * handle, const char * name)
}
}
if (find_egl_ptr && real_func && !is_angle) {
if (find_egl_ptr && real_func) {
func = find_egl_ptr(name);
if (func) {
//fprintf(stderr,"%s: local: %s\n", __func__ , name);

@ -3,13 +3,12 @@
#include <functional>
#include <sstream>
#include <cmath>
#include <map>
#include "overlay.h"
#include "overlay_params.h"
#include "hud_elements.h"
#include "logging.h"
#include "battery.h"
#include "device.h"
#include "gamepad.h"
#include "cpu.h"
#include "gpu.h"
#include "memory.h"
@ -20,11 +19,6 @@
#include <IconsForkAwesome.h>
#include "version.h"
#include "blacklist.h"
#ifdef __linux__
#include "implot.h"
#endif
#include "amdgpu.h"
#include "fps_metrics.h"
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
@ -97,8 +91,6 @@ void HudElements::convert_colors(const struct overlay_params& params)
HUDElements.colors.fps_value_low = convert(params.fps_color[0]);
HUDElements.colors.fps_value_med = convert(params.fps_color[1]);
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);
ImGuiStyle& style = ImGui::GetStyle();
style.Colors[ImGuiCol_PlotLines] = convert(params.frametime_color);
@ -117,7 +109,7 @@ void HudElements::convert_colors(bool do_conv, const struct overlay_params& para
void HudElements::TextColored(ImVec4 col, const char *fmt, ...){
auto textColor = ImGui::ColorConvertFloat4ToU32(col);
char buffer[128] {};
char buffer[32] {};
va_list args;
va_start(args, fmt);
@ -162,17 +154,8 @@ static void ImGuiTableSetColumnIndex(int column)
void HudElements::time(){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_time]){
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] &&
!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] &&
!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_time_no_label]){
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.text, "Time");
ImguiNextColumnOrNewRow();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", HUDElements.sw_stats->time.c_str());
} else {
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.text, "%s", HUDElements.sw_stats->time.c_str());
}
ImguiNextColumnFirstItem();
HUDElements.TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.00f), "%s", HUDElements.sw_stats->time.c_str());
}
}
@ -248,22 +231,13 @@ void HudElements::gpu_stats(){
ImGui::PopFont();
}
if (HUDElements.vendorID == 0x1002 || HUDElements.vendorID == 0x10de){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] && cpuStats.cpu_type != "APU"){
ImguiNextColumnOrNewRow();
right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu_info.fan_speed);
ImGui::SameLine(0, 1.0f);
if (gpu_info.fan_rpm) {
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "RPM");
} else {
HUDElements.TextColored(HUDElements.colors.text, "%%");
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::SameLine(0, 1.0f);
HUDElements.TextColored(HUDElements.colors.text, "FAN");
}
ImGui::PopFont();
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] && cpuStats.cpu_type != "APU"){
ImguiNextColumnOrNewRow();
right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu_info.fan_speed);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "RPM");
ImGui::PopFont();
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock]){
@ -499,12 +473,10 @@ void HudElements::vram(){
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", gpu_info.memoryUsed + gpu_info.gtt_used);
else
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", gpu_info.memoryUsed);
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "GiB");
ImGui::PopFont();
}
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "GiB");
ImGui::PopFont();
if (gpu_info.memory_temp > -1 && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp]) {
ImguiNextColumnOrNewRow();
@ -732,17 +704,6 @@ void HudElements::wine(){
}
}
static inline double TransformForward_Custom(double v, void*) {
if (v > 50)
v = 49.9;
return v;
}
static inline double TransformInverse_Custom(double v, void*) {
return v;
}
void HudElements::frame_timing(){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing]){
ImguiNextColumnFirstItem();
@ -753,7 +714,6 @@ void HudElements::frame_timing(){
ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1);
ImGui::Dummy(ImVec2(0.0f, real_font_size.y));
right_aligned_text(HUDElements.colors.text, ImGui::GetContentRegionAvail().x, "min: %.1fms, max: %.1fms", min_frametime, max_frametime);
ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));
ImguiNextColumnFirstItem();
}
char hash[40];
@ -766,7 +726,7 @@ void HudElements::frame_timing(){
float width, height = 0;
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]){
width = 150;
height = HUDElements.params->font_size * 0.85;
height = HUDElements.params->font_size;
} else {
width = ImGui::GetWindowContentRegionWidth();
height = max_time;
@ -776,79 +736,23 @@ void HudElements::frame_timing(){
min_time = min_frametime;
max_time = max_frametime;
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed]){
height = 125;
}
if (ImGui::BeginChild("my_child_window", ImVec2(width, height), false, ImGuiWindowFlags_NoDecoration)) {
if (ImGui::BeginChild("my_child_window", ImVec2(width, height))) {
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){
ImGui::PlotHistogram(hash, get_time_stat, HUDElements.sw_stats,
ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0,
NULL, min_time, max_time,
ImVec2(width, height));
} else {
#ifndef __linux__
ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats,
ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0,
NULL, min_time, max_time,
ImVec2(width, height));
#else
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) {
ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats,
ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0,
NULL, min_time, max_time,
ImVec2(width, height));
} else {
if (ImPlot::BeginPlot("My Plot", ImVec2(width, height), ImPlotFlags_CanvasOnly | ImPlotFlags_NoInputs)) {
ImPlotStyle& style = ImPlot::GetStyle();
style.Colors[ImPlotCol_PlotBg] = ImVec4(0.92f, 0.92f, 0.95f, 0.00f);
style.Colors[ImPlotCol_AxisGrid] = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
style.Colors[ImPlotCol_AxisTick] = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
ImPlotAxisFlags ax_flags_x = ImPlotAxisFlags_NoDecorations;
ImPlotAxisFlags ax_flags_y = ImPlotAxisFlags_NoDecorations;
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed])
ax_flags_y = ImPlotAxisFlags_Opposite | ImPlotAxisFlags_NoMenus;
ImPlot::SetupAxes(nullptr, nullptr, ax_flags_x, ax_flags_y);
ImPlot::SetupAxisScale(ImAxis_Y1, TransformForward_Custom, TransformInverse_Custom);
ImPlot::SetupAxesLimits(0, 200, min_time, max_time);
ImPlot::SetNextLineStyle(HUDElements.colors.frametime, 1.5);
ImPlot::PlotLine("frametime line", frametime_data.data(), frametime_data.size());
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status_graph] && throttling){
ImPlot::SetNextLineStyle(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), 1.5);
ImPlot::PlotLine("power line", throttling->power.data(), throttling->power.size());
ImPlot::SetNextLineStyle(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.5);
ImPlot::PlotLine("thermal line", throttling->thermal.data(), throttling->thermal.size());
}
ImPlot::EndPlot();
}
}
#endif
}
}
ImGui::EndChild();
#ifdef __linux__
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status_graph] && throttling){
ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));
if (throttling->power_throttling()) {
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "%s", ICON_FK_SQUARE);
ImGui::SameLine();
ImGui::Text("Power throttling");
}
ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));
if (throttling->thermal_throttling()) {
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", ICON_FK_SQUARE);
ImGui::SameLine();
ImGui::Text("Thermal throttling");
}
}
ImGui::PopFont();
ImGui::PopStyleColor();
#endif
}
}
@ -902,24 +806,13 @@ void HudElements::show_fps_limit(){
}
void HudElements::custom_text_center(){
if (HUDElements.place >= 0 &&
static_cast<size_t>(HUDElements.place) < HUDElements.ordered_functions.size()) {
if (!HUDElements.sw_stats || !HUDElements.sw_stats->font1) {
return;
}
ImguiNextColumnFirstItem();
ImGui::PushFont(HUDElements.sw_stats->font1);
const std::string& value = HUDElements.ordered_functions[HUDElements.place].value;
center_text(value);
HUDElements.TextColored(HUDElements.colors.text, "%s", value.c_str());
ImGui::NewLine();
ImGui::PopFont();
}
ImguiNextColumnFirstItem();
ImGui::PushFont(HUDElements.sw_stats->font1);
const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
center_text(value);
HUDElements.TextColored(HUDElements.colors.text, "%s",value.c_str());
ImGui::NewLine();
ImGui::PopFont();
}
void HudElements::custom_text(){
@ -927,11 +820,9 @@ void HudElements::custom_text(){
ImGui::PushFont(HUDElements.sw_stats->font1);
const char* value;
if (size_t(HUDElements.place) < HUDElements.ordered_functions.size())
value = HUDElements.ordered_functions[HUDElements.place].value.c_str();
else {
ImGui::PopFont();
value = HUDElements.ordered_functions[HUDElements.place].second.c_str();
else
return;
}
HUDElements.TextColored(HUDElements.colors.text, "%s",value);
ImGui::PopFont();
}
@ -941,9 +832,8 @@ void HudElements::_exec(){
ImGui::PushFont(HUDElements.sw_stats->font1);
ImguiNextColumnFirstItem();
for (auto& item : HUDElements.exec_list){
if (item.pos == HUDElements.place){
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", item.ret.c_str());
}
if (item.pos == HUDElements.place)
HUDElements.TextColored(HUDElements.colors.text, "%s", item.ret.c_str());
}
ImGui::PopFont();
}
@ -1004,10 +894,7 @@ void HudElements::battery(){
if (Battery_Stats.current_watt != 0) {
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_watt]){
ImguiNextColumnOrNewRow();
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] && Battery_Stats.current_watt >= 10.0f)
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", Battery_Stats.current_watt);
else
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", Battery_Stats.current_watt);
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", Battery_Stats.current_watt);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "W");
@ -1085,24 +972,25 @@ void HudElements::gamescope_frame_timing(){
static double min_time = 0.0f;
static double max_time = 50.0f;
if (HUDElements.gamescope_debug_app.size() > 0 && HUDElements.gamescope_debug_app.back() > -1){
ImguiNextColumnFirstItem();
ImGui::Dummy(ImVec2(0.0f, real_font_size.y));
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.engine, "%s", "App");
ImGui::TableNextRow();
ImGui::Dummy(ImVec2(0.0f, real_font_size.y));
auto min = std::min_element(HUDElements.gamescope_debug_app.begin(),
HUDElements.gamescope_debug_app.end());
auto max = std::max_element(HUDElements.gamescope_debug_app.begin(),
HUDElements.gamescope_debug_app.end());
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::Dummy(ImVec2(0.0f, real_font_size.y));
HUDElements.TextColored(HUDElements.colors.engine, "%s", "App");
ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1);
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, "min: %.1fms, max: %.1fms", min[0], max[0]);
ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));
ImguiNextColumnFirstItem();
ImGui::PopFont();
ImguiNextColumnFirstItem();
char hash[40];
snprintf(hash, sizeof(hash), "##%s", overlay_param_names[OVERLAY_PARAM_ENABLED_frame_timing]);
HUDElements.sw_stats->stat_selector = OVERLAY_PLOTS_frame_timing;
HUDElements.sw_stats->time_dividor = 1000000.0f; /* ns -> ms */
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
if (ImGui::BeginChild("gamescope_app_window", ImVec2(ImGui::GetWindowContentRegionWidth(), 50))) {
ImGui::PlotLines("", HUDElements.gamescope_debug_app.data(),
@ -1141,24 +1029,23 @@ void HudElements::gamescope_frame_timing(){
}
}
void HudElements::device_battery()
void HudElements::gamepad_battery()
{
#ifdef __linux__
std::unique_lock<std::mutex> l(device_lock);
if (!HUDElements.params->device_battery.empty()) {
if (device_found) {
for (int i = 0; i < device_count; i++) {
std::string battery = device_data[i].battery;
std::string name = device_data[i].name;
std::string battery_percent = device_data[i].battery_percent;
bool report_percent = device_data[i].report_percent;
bool charging = device_data[i].is_charging;
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery]) {
if (gamepad_found) {
for (int i = 0; i < gamepad_count; i++) {
std::string battery = gamepad_data[i].battery;
std::string name = gamepad_data[i].name;
std::string battery_percent = gamepad_data[i].battery_percent;
bool report_percent = gamepad_data[i].report_percent;
bool charging = gamepad_data[i].is_charging;
ImguiNextColumnFirstItem();
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.engine, "%s", name.c_str());
ImguiNextColumnOrNewRow();
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_device_battery_icon]) {
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery_icon]) {
if (charging)
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB);
else {
@ -1189,8 +1076,6 @@ void HudElements::device_battery()
right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, "%s", battery.c_str());
}
}
if (device_count > 1 && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])
ImGui::TableNextRow();
ImGui::PopFont();
}
}
@ -1263,7 +1148,7 @@ void HudElements::duration(){
void HudElements::graphs(){
ImguiNextColumnFirstItem();
ImGui::Dummy(ImVec2(0.0f, real_font_size.y));
const std::string& value = HUDElements.ordered_functions[HUDElements.place].value;
const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
assert(kMaxGraphEntries >= graph_data.size());
std::vector<float> arr(kMaxGraphEntries - graph_data.size());
@ -1359,6 +1244,7 @@ void HudElements::graphs(){
ImGui::PopFont();
ImGui::Dummy(ImVec2(0.0f,5.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImguiNextColumnOrNewRow();
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){
ImGui::PlotLines("", arr.data(),
arr.size(), 0,
@ -1386,181 +1272,64 @@ void HudElements::exec_name(){
}
}
void HudElements::fps_metrics(){
for (auto& metric : fpsmetrics->metrics){
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.engine, "%s", metric.display_name.c_str());
ImguiNextColumnOrNewRow();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", metric.value);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "FPS");
ImGui::PopFont();
ImguiNextColumnOrNewRow();
}
}
void HudElements::hdr() {
if (HUDElements.hdr_status > 0) {
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.engine, "%s", "HDR");
ImguiNextColumnOrNewRow();
right_aligned_text(HUDElements.colors.fps_value_high, HUDElements.ralign_width, "ON");
}
}
void HudElements::refresh_rate() {
if (HUDElements.refresh > 0) {
ImGui::PushFont(HUDElements.sw_stats->font1);
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.engine, "%s", "Display Hz");
ImguiNextColumnOrNewRow();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", HUDElements.refresh);
ImGui::PopFont();
}
}
void HudElements::winesync() {
if (!HUDElements.winesync_ptr)
HUDElements.winesync_ptr = std::make_unique<WineSync>();
if (HUDElements.winesync_ptr->valid()) {
ImGui::PushFont(HUDElements.sw_stats->font1);
ImguiNextColumnFirstItem();
HUDElements.TextColored(HUDElements.colors.engine, "%s", "WSYNC");
ImguiNextColumnOrNewRow();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", HUDElements.winesync_ptr->get_method().c_str());
ImGui::PopFont();
}
}
void HudElements::present_mode() {
ImguiNextColumnFirstItem();
ImGui::PushFont(HUDElements.sw_stats->font1);
if (HUDElements.is_vulkan)
HUDElements.TextColored(HUDElements.colors.engine, "%s", "Present Mode");
else
HUDElements.TextColored(HUDElements.colors.engine, "%s", "VSYNC");
ImguiNextColumnOrNewRow();
HUDElements.TextColored(HUDElements.colors.text, "%s\n", HUDElements.get_present_mode().c_str());
ImGui::PopFont();
}
void HudElements::network() {
#ifdef __linux__
if (HUDElements.net && HUDElements.net->should_reset)
HUDElements.net.reset(new Net);
if (!HUDElements.net)
HUDElements.net = std::make_unique<Net>();
for (auto& iface : HUDElements.net->interfaces){
ImGui::TableNextRow();
ImGui::TableNextColumn();
HUDElements.TextColored(HUDElements.colors.network, "%.8s", iface.name.c_str());
ImGui::TableNextColumn();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", iface.txBps / 1000.f);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "KB/s %s", ICON_FK_ARROW_UP);
ImGui::PopFont();
ImGui::TableNextColumn();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", iface.rxBps / 1000.f);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
HUDElements.TextColored(HUDElements.colors.text, "KB/s %s", ICON_FK_ARROW_DOWN);
ImGui::PopFont();
}
#endif
}
void HudElements::sort_elements(const std::pair<std::string, std::string>& option) {
void HudElements::sort_elements(const std::pair<std::string, std::string>& option){
const auto& param = option.first;
const auto& value = option.second;
// Initialize a map of display parameters and their corresponding functions.
const std::map<std::string, Function> display_params = {
{"version", {version}},
{"time", {time}},
{"gpu_stats", {gpu_stats}},
{"cpu_stats", {cpu_stats}},
{"core_load", {core_load}},
{"io_read", {io_stats}},
{"io_write", {io_stats}},
{"arch", {arch}},
{"wine", {wine}},
{"procmem", {procmem}},
{"gamemode", {gamemode}},
{"vkbasalt", {vkbasalt}},
{"engine_version", {engine_version}},
{"vulkan_driver", {vulkan_driver}},
{"resolution", {resolution}},
{"show_fps_limit", {show_fps_limit}},
{"vram", {vram}},
{"ram", {ram}},
{"fps", {fps}},
{"gpu_name", {gpu_name}},
{"frame_timing", {frame_timing}},
{"media_player", {media_player}},
{"custom_text", {custom_text}},
{"custom_text_center", {custom_text_center}},
{"exec", {_exec}},
{"battery", {battery}},
{"fps_only", {fps_only}},
{"fsr", {gamescope_fsr}},
{"debug", {gamescope_frame_timing}},
{"device_battery", {device_battery}},
{"frame_count", {frame_count}},
{"fan", {fan}},
{"throttling_status", {throttling_status}},
{"exec_name", {exec_name}},
{"duration", {duration}},
{"graphs", {graphs}},
{"fps_metrics", {fps_metrics}},
{"hdr", {hdr}},
{"refresh_rate", {refresh_rate}},
{"winesync", {winesync}},
{"present_mode", {present_mode}},
{"network", {network}}
};
auto check_param = display_params.find(param);
if (check_param != display_params.end()) {
const Function& func = check_param->second;
if (param == "debug") {
ordered_functions.push_back({gamescope_frame_timing, "gamescope_frame_timing", value});
} else if (param == "fsr") {
ordered_functions.push_back({gamescope_fsr, "gamescope_fsr", value});
} else if (param == "io_read" || param == "io_write") {
// Don't add twice
if (std::none_of(ordered_functions.begin(), ordered_functions.end(),
[](const auto& a) { return a.name == "io_stats"; })) {
ordered_functions.push_back({io_stats, "io_stats", value});
}
} else if (param == "exec") {
ordered_functions.push_back({_exec, "exec", value});
exec_list.push_back({int(ordered_functions.size() - 1), value});
} else if (param == "graphs") {
// Handle graphs parameter
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs]) {
HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs] = true;
}
auto values = str_tokenize(value);
for (auto& val : values) {
if (find(permitted_params.begin(), permitted_params.end(), val) != permitted_params.end()) {
ordered_functions.push_back({graphs, "graph: " + val, val});
} else {
SPDLOG_ERROR("Unrecognized graph type: {}", val);
}
// Use this to always add to front of vector
//ordered_functions.insert(ordered_functions.begin(),std::make_pair(param,value));
if (param == "version") { ordered_functions.push_back({version, value}); }
if (param == "time") { ordered_functions.push_back({time, value}); }
if (param == "gpu_stats") { ordered_functions.push_back({gpu_stats, value}); }
if (param == "cpu_stats") { ordered_functions.push_back({cpu_stats, value}); }
if (param == "core_load") { ordered_functions.push_back({core_load, value}); }
if (param == "io_read" || param == "io_write") {
// Don't add twice
if (std::find_if(ordered_functions.begin(), ordered_functions.end(), [](const auto& a) -> bool { return a.first == io_stats; }) != ordered_functions.end())
return;
ordered_functions.push_back({io_stats, value});
}
if (param == "arch") { ordered_functions.push_back({arch, value}); }
if (param == "wine") { ordered_functions.push_back({wine, value}); }
if (param == "procmem") { ordered_functions.push_back({procmem, value}); }
if (param == "gamemode") { ordered_functions.push_back({gamemode, value}); }
if (param == "vkbasalt") { ordered_functions.push_back({vkbasalt, value}); }
if (param == "engine_version") { ordered_functions.push_back({engine_version, value}); }
if (param == "vulkan_driver") { ordered_functions.push_back({vulkan_driver, value}); }
if (param == "resolution") { ordered_functions.push_back({resolution, value}); }
if (param == "show_fps_limit") { ordered_functions.push_back({show_fps_limit, value}); }
if (param == "vram") { ordered_functions.push_back({vram, value}); }
if (param == "ram") { ordered_functions.push_back({ram, value}); }
if (param == "fps") { ordered_functions.push_back({fps, value}); }
if (param == "gpu_name") { ordered_functions.push_back({gpu_name, value}); }
if (param == "frame_timing") { ordered_functions.push_back({frame_timing, value}); }
if (param == "media_player") { ordered_functions.push_back({media_player, value}); }
if (param == "custom_text") { ordered_functions.push_back({custom_text, value}); }
if (param == "custom_text_center") { ordered_functions.push_back({custom_text_center, value}); }
if (param == "exec") { ordered_functions.push_back({_exec, value});
exec_list.push_back({int(ordered_functions.size() - 1), value}); }
if (param == "battery") { ordered_functions.push_back({battery, value}); }
if (param == "fps_only") { ordered_functions.push_back({fps_only, value}); }
if (param == "fsr") { ordered_functions.push_back({gamescope_fsr, value}); }
if (param == "debug") { ordered_functions.push_back({gamescope_frame_timing, value}); }
if (param == "gamepad_battery") { ordered_functions.push_back({gamepad_battery, value}); }
if (param == "frame_count") { ordered_functions.push_back({frame_count, value}); }
if (param == "fan") { ordered_functions.push_back({fan, value}); }
if (param == "throttling_status") { ordered_functions.push_back({throttling_status, value}); }
if (param == "exec_name") { ordered_functions.push_back({exec_name, value}); }
if (param == "duration") { ordered_functions.push_back({duration, value}); }
if (param == "graphs"){
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs])
HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_graphs] = true;
auto values = str_tokenize(value);
for (auto& value : values) {
if (find(permitted_params.begin(), permitted_params.end(), value) != permitted_params.end())
ordered_functions.push_back({graphs, value});
else
{
spdlog::error("Unrecognized graph type: {}", value);
}
} else {
// Use this to always add to the front of the vector
// ordered_functions.insert(ordered_functions.begin(), std::make_pair(param, value));
ordered_functions.push_back({func.run, param, value});
}
}
return;
@ -1570,96 +1339,70 @@ void HudElements::legacy_elements(){
string value = "NULL";
ordered_functions.clear();
if (params->enabled[OVERLAY_PARAM_ENABLED_time])
ordered_functions.push_back({time, "time", value});
ordered_functions.push_back({time, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_version])
ordered_functions.push_back({version, "version", value});
ordered_functions.push_back({version, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats])
ordered_functions.push_back({gpu_stats, "gpu_stats", value});
ordered_functions.push_back({gpu_stats, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats])
ordered_functions.push_back({cpu_stats, "cpu_stats", value});
ordered_functions.push_back({cpu_stats, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_core_load])
ordered_functions.push_back({core_load, "core_load", value});
ordered_functions.push_back({core_load, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_io_read] || params->enabled[OVERLAY_PARAM_ENABLED_io_write])
ordered_functions.push_back({io_stats, "io_stats", value});
ordered_functions.push_back({io_stats, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_vram])
ordered_functions.push_back({vram, "vram", value});
ordered_functions.push_back({vram, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_ram])
ordered_functions.push_back({ram, "ram", value});
if (!params->network.empty())
ordered_functions.push_back({network, "network", value});
ordered_functions.push_back({ram, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_battery])
ordered_functions.push_back({battery, "battery", value});
ordered_functions.push_back({battery, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_fan])
ordered_functions.push_back({fan, "fan", value});
ordered_functions.push_back({fan, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_fsr])
ordered_functions.push_back({gamescope_fsr, "gamescope_fsr", value});
if (params->enabled[OVERLAY_PARAM_ENABLED_hdr])
ordered_functions.push_back({hdr, "hdr", value});
ordered_functions.push_back({gamescope_fsr, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_throttling_status])
ordered_functions.push_back({throttling_status, "throttling_status", value});
ordered_functions.push_back({throttling_status, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_fps])
ordered_functions.push_back({fps, "fps", value});
for (const auto& pair : options) {
if (pair.first.find("graphs") != std::string::npos) {
std::stringstream ss(pair.second);
std::string token;
while (std::getline(ss, token, ',')){
ordered_functions.push_back({graphs, "graphs", token});
}
}
}
if (!params->fps_metrics.empty())
ordered_functions.push_back({fps_metrics, "fps_metrics", value});
ordered_functions.push_back({fps, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_fps_only])
ordered_functions.push_back({fps_only, "fps_only", value});
ordered_functions.push_back({fps_only, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_engine_version])
ordered_functions.push_back({engine_version, "engine_version", value});
ordered_functions.push_back({engine_version, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_name])
ordered_functions.push_back({gpu_name, "gpu_name", value});
ordered_functions.push_back({gpu_name, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_vulkan_driver])
ordered_functions.push_back({vulkan_driver, "vulkan_driver", value});
ordered_functions.push_back({vulkan_driver, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_arch])
ordered_functions.push_back({arch, "arch", value});
ordered_functions.push_back({arch, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_wine])
ordered_functions.push_back({wine, "wine", value});
ordered_functions.push_back({wine, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_frame_timing])
ordered_functions.push_back({frame_timing, "frame_timing", value});
ordered_functions.push_back({frame_timing, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_frame_count])
ordered_functions.push_back({frame_count, "frame_count", value});
ordered_functions.push_back({frame_count, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_debug] && !params->enabled[OVERLAY_PARAM_ENABLED_horizontal])
ordered_functions.push_back({gamescope_frame_timing, "gamescope_frame_timing", value});
ordered_functions.push_back({gamescope_frame_timing, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_gamemode])
ordered_functions.push_back({gamemode, "gamemode", value});
ordered_functions.push_back({gamemode, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_vkbasalt])
ordered_functions.push_back({vkbasalt, "vkbasalt", value});
ordered_functions.push_back({vkbasalt, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_show_fps_limit])
ordered_functions.push_back({show_fps_limit, "show_fps_limit", value});
ordered_functions.push_back({show_fps_limit, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_resolution])
ordered_functions.push_back({resolution, "resolution", value});
if (!params->device_battery.empty() )
ordered_functions.push_back({device_battery, "device_battery", value});
ordered_functions.push_back({resolution, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery])
ordered_functions.push_back({gamepad_battery, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_media_player])
ordered_functions.push_back({media_player, "media_player", value});
ordered_functions.push_back({media_player, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_exec_name])
ordered_functions.push_back({exec_name, "exec_name", value});
ordered_functions.push_back({exec_name, value});
if (params->enabled[OVERLAY_PARAM_ENABLED_duration])
ordered_functions.push_back({duration, "duration", value});
if (params->enabled[OVERLAY_PARAM_ENABLED_winesync])
ordered_functions.push_back({winesync, "winesync", value});
if (params->enabled[OVERLAY_PARAM_ENABLED_present_mode])
ordered_functions.push_back({present_mode, "present_mode", value});
if (params->enabled[OVERLAY_PARAM_ENABLED_refresh_rate])
ordered_functions.push_back({refresh_rate, "refresh_rate", value});
ordered_functions.push_back({duration, value});
}
void HudElements::update_exec(){
#ifdef __linux__
if (!HUDElements.shell)
HUDElements.shell = std::make_unique<Shell>();
for(auto& item : exec_list)
item.ret = HUDElements.shell->exec(item.value + "\n");
#endif
item.ret = exec(item.value);
}
HudElements HUDElements;

@ -4,19 +4,6 @@
#include <utility>
#include <imgui.h>
#include "timing.hpp"
#include <functional>
#include "winesync.h"
#include "vulkan/vulkan.h"
#include <array>
#include "net.h"
#include "overlay_params.h"
#include "shell.h"
struct Function {
std::function<void()> run; // Using std::function instead of a raw function pointer for more flexibility
std::string name;
std::string value;
};
struct overlay_params;
class HudElements{
@ -31,7 +18,7 @@ class HudElements{
float ralign_width;
float old_scale;
float res_width, res_height;
bool is_vulkan = true, gamemode_bol = false, vkbasalt_bol = false;
bool is_vulkan, gamemode_bol = false, vkbasalt_bol = false;
int place;
int text_column = 1;
int table_columns_count = 0;
@ -39,7 +26,7 @@ class HudElements{
int g_fsrSharpness = -1;
Clock::time_point last_exec;
std::vector<std::pair<std::string, std::string>> options;
std::vector<Function> ordered_functions;
std::vector<std::pair<void(*)(), std::string >> ordered_functions;
std::vector<float> gamescope_debug_latency {};
std::vector<float> gamescope_debug_app {};
int min, max, gpu_core_max, gpu_mem_max, cpu_temp_max, gpu_temp_max;
@ -49,14 +36,6 @@ class HudElements{
};
std::vector<exec_entry> exec_list;
std::chrono::steady_clock::time_point overlay_start = std::chrono::steady_clock::now();
uint32_t vendorID;
int hdr_status = 0;
int refresh = 0;
std::unique_ptr<WineSync> winesync_ptr = nullptr;
std::unique_ptr<Net> net = nullptr;
#ifdef __linux__
std::unique_ptr<Shell> shell = nullptr;
#endif
void sort_elements(const std::pair<std::string, std::string>& option);
void legacy_elements();
@ -91,18 +70,12 @@ class HudElements{
static void fps_only();
static void gamescope_fsr();
static void gamescope_frame_timing();
static void device_battery();
static void gamepad_battery();
static void frame_count();
static void fan();
static void throttling_status();
static void exec_name();
static void duration();
static void fps_metrics();
static void hdr();
static void refresh_rate();
static void winesync();
static void present_mode();
static void network();
void convert_colors(const struct overlay_params& params);
void convert_colors(bool do_conv, const struct overlay_params& params);
@ -129,42 +102,10 @@ class HudElements{
cpu_load_high,
fps_value_low,
fps_value_med,
fps_value_high,
text_outline,
network;
fps_value_high;
} colors {};
void TextColored(ImVec4 col, const char *fmt, ...);
std::array<VkPresentModeKHR, 6> presentModes = {
VK_PRESENT_MODE_FIFO_RELAXED_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_MAILBOX_KHR,
VK_PRESENT_MODE_FIFO_KHR,
VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR};
std::map<VkPresentModeKHR, std::string> presentModeMap = {
{VK_PRESENT_MODE_IMMEDIATE_KHR, "IMMEDIATE"},
{VK_PRESENT_MODE_MAILBOX_KHR, "MAILBOX"},
{VK_PRESENT_MODE_FIFO_KHR, "FIFO"},
{VK_PRESENT_MODE_FIFO_RELAXED_KHR, "FIFO Relaxed"},
{VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "DEMAND"},
{VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "CONTINUOUS"}
};
VkPresentModeKHR cur_present_mode;
std::string get_present_mode(){
if (is_vulkan)
return presentModeMap[cur_present_mode];
// TODO: the opengl side is probably not as solid.
// But it also might not be possible to figure out if vsync
// is on or off unless we specify it.
else
return params->gl_vsync == 0 ? "OFF" : "ON";
}
};
extern HudElements HUDElements;

@ -1,8 +1,21 @@
#include "intel.h"
std::unique_ptr<Intel> intel;
void Intel::intel_gpu_thread(){
init = true;
#include <thread>
#include "overlay.h"
#include "gpu.h"
#include "spdlog/spdlog.h"
#include <nlohmann/json.hpp>
#include <sys/stat.h>
#include <filesystem.h>
#include <inttypes.h>
using json = nlohmann::json;
namespace fs = ghc::filesystem;
static bool init_intel = false;
struct gpuInfo gpu_info_intel {};
FILE* fdinfo;
static void intelGpuThread(bool runtime){
init_intel = true;
static char stdout_buffer[1024];
static FILE* intel_gpu_top;
if (runtime)
@ -50,8 +63,6 @@ void Intel::intel_gpu_thread(){
num_line = 0;
}
num_iterations++;
if (stop)
break;
}
int exitcode = pclose(intel_gpu_top) / 256;
@ -62,10 +73,12 @@ void Intel::intel_gpu_thread(){
if (exitcode == 1)
SPDLOG_INFO("Missing permissions for '{}'", "intel_gpu_top");
SPDLOG_INFO("Disabling gpu_stats");
_params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = false;
}
}
uint64_t Intel::get_gpu_time() {
static uint64_t get_gpu_time() {
rewind(fdinfo);
fflush(fdinfo);
char line[256];
@ -78,7 +91,7 @@ uint64_t Intel::get_gpu_time() {
return val;
}
FILE* Intel::find_fd() {
static FILE* find_fd() {
DIR* dir = opendir("/proc/self/fdinfo");
if (!dir) {
perror("Failed to open directory");
@ -99,6 +112,7 @@ FILE* Intel::find_fd() {
if (found_driver){
if(strstr(line, "drm-engine-render")){
sscanf(line, "drm-engine-render: %" SCNu64 " ns", &val);
if (val > 0)
return file;
}
}
@ -110,23 +124,37 @@ FILE* Intel::find_fd() {
return NULL; // Return NULL if no matching file is found
}
void Intel::get_fdinfo(){
static uint64_t previous_gpu_time, previous_time, now, gpu_time_now;
gpu_time_now = get_gpu_time();
now = os_time_get_nano();
if (previous_time && previous_gpu_time && gpu_time_now > previous_gpu_time){
float time_since_last = now - previous_time;
float gpu_since_last = gpu_time_now - previous_gpu_time;
auto result = int((gpu_since_last / time_since_last) * 100);
if (result > 100)
result = 100;
gpu_info_intel.load = result;
previous_gpu_time = gpu_time_now;
previous_time = now;
} else {
previous_gpu_time = gpu_time_now;
previous_time = now;
void getIntelGpuInfo(){
if (!init_intel){
fdinfo = find_fd();
static bool runtime = false;
static struct stat buffer;
if (stat("/run/pressure-vessel", &buffer) == 0)
runtime = true;
std::thread(intelGpuThread, runtime).detach();
}
if (fdinfo){
static uint64_t previous_gpu_time, previous_time, now, gpu_time_now;
gpu_time_now = get_gpu_time();
now = os_time_get_nano();
if (previous_time && previous_gpu_time && gpu_time_now > previous_gpu_time){
float time_since_last = now - previous_time;
float gpu_since_last = gpu_time_now - previous_gpu_time;
auto result = int((gpu_since_last / time_since_last) * 100);
if (result > 100)
result = 100;
gpu_info_intel.load = result;
previous_gpu_time = gpu_time_now;
previous_time = now;
} else {
previous_gpu_time = gpu_time_now;
previous_time = now;
}
}
gpu_info = gpu_info_intel;
}

@ -1,51 +0,0 @@
#include <sys/stat.h>
#include <thread>
#include <nlohmann/json.hpp>
#include <filesystem.h>
#include <inttypes.h>
#include <mesa/util/os_time.h>
#include <spdlog/spdlog.h>
#include "gpu.h"
#include "hud_elements.h"
using json = nlohmann::json;
namespace fs = ghc::filesystem;
class Intel {
private:
bool init = false;
bool runtime = false;
bool stop = false;
struct gpuInfo gpu_info_intel {};
FILE* fdinfo;
struct stat stat_buffer;
std::thread thread;
FILE* find_fd();
void intel_gpu_thread();
uint64_t get_gpu_time();
void get_fdinfo();
public:
Intel() {
if (stat("/run/pressure-vessel", &stat_buffer) == 0)
runtime = true;
fdinfo = find_fd();
// thread = std::thread(&Intel::intel_gpu_thread, this);
}
void update() {
if (fdinfo)
get_fdinfo();
gpu_info = gpu_info_intel;
}
// ~Intel(){
// stop = true;
// thread.join();
// }
};
extern std::unique_ptr<Intel> intel;

@ -1,15 +1,8 @@
#include <cstdint>
#include <cstring>
#include <array>
#include <algorithm>
#include <unistd.h>
#include "overlay.h"
#include "timing.hpp"
#include "logging.h"
#include "keybinds.h"
#include "fps_metrics.h"
Clock::time_point last_f2_press, toggle_fps_limit_press, toggle_preset_press, last_f12_press, reload_cfg_press, last_upload_press;
void check_keybinds(struct overlay_params& params, uint32_t vendorID){
using namespace std::chrono_literals;
@ -26,7 +19,7 @@ void check_keybinds(struct overlay_params& params, uint32_t vendorID){
return;
last_check = now;
const auto keyPressDelay = 400ms;
auto keyPressDelay = 400ms;
if (elapsedF2 >= keyPressDelay &&
keys_are_pressed(params.toggle_logging)) {
@ -101,11 +94,4 @@ void check_keybinds(struct overlay_params& params, uint32_t vendorID){
next_hud_position(params);
last_f12_press = now;
}
if (elapsedF12 >= keyPressDelay &&
keys_are_pressed(params.reset_fps_metrics)) {
last_f12_press = now;
if (fpsmetrics)
fpsmetrics->reset_metrics();
}
}

@ -6,50 +6,37 @@
#include "shared_x11.h"
#include "loaders/loader_x11.h"
#endif
#ifdef HAVE_WAYLAND
#include "wayland_hook.h"
#endif
#ifndef KeySym
typedef unsigned long KeySym;
#endif
#if defined(HAVE_X11) || defined(HAVE_WAYLAND)
static inline bool keys_are_pressed(const std::vector<KeySym>& keys)
{
#if defined(HAVE_WAYLAND)
if(wl_display_ptr && wl_handle)
{
update_wl_queue();
Clock::time_point last_f2_press, toggle_fps_limit_press, toggle_preset_press, last_f12_press, reload_cfg_press, last_upload_press;
if(wl_pressed_keys.size() == keys.size() && wl_pressed_keys == keys)
return true;
}
#endif
#if defined(HAVE_X11)
static inline bool keys_are_pressed(const std::vector<KeySym>& keys) {
#if defined(HAVE_X11)
if (init_x11())
{
char keys_return[32];
size_t pressed = 0;
if (!init_x11())
return false;
auto libx11 = get_libx11();
libx11->XQueryKeymap(get_xdisplay(), keys_return);
char keys_return[32];
size_t pressed = 0;
for (KeySym ks : keys) {
KeyCode kc2 = libx11->XKeysymToKeycode(get_xdisplay(), ks);
auto libx11 = get_libx11();
libx11->XQueryKeymap(get_xdisplay(), keys_return);
bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));
for (KeySym ks : keys) {
KeyCode kc2 = libx11->XKeysymToKeycode(get_xdisplay(), ks);
if (isPressed)
pressed++;
}
bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));
if (pressed > 0 && pressed == keys.size()) {
return true;
}
if (isPressed)
pressed++;
}
if (pressed > 0 && pressed == keys.size()) {
return true;
}
#endif
return false;
}
@ -69,6 +56,10 @@ static inline bool keys_are_pressed(const std::vector<KeySym>& keys) {
return false;
}
#else // XXX: Add wayland support
static inline bool keys_are_pressed(const std::vector<KeySym>& keys) {
return false;
}
#endif
#endif //MANGOHUD_KEYBINDS_H

@ -36,7 +36,7 @@ bool libnvctrl_loader::Load(const std::string& library_name) {
#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN)
library_ = dlopen(library_name.c_str(), RTLD_LAZY);
if (!library_) {
SPDLOG_DEBUG("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror());
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror());
return false;
}
@ -80,14 +80,6 @@ bool libnvctrl_loader::Load(const std::string& library_name) {
return false;
}
XNVCTRLQueryTargetCount =
reinterpret_cast<decltype(this->XNVCTRLQueryTargetCount)>(
dlsym(library_, "XNVCTRLQueryTargetCount"));
if (!XNVCTRLQueryTargetCount) {
CleanUp(true);
return false;
}
#endif
#if defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED)

@ -24,7 +24,6 @@ class libnvctrl_loader {
decltype(&::XNVCTRLQueryAttribute) XNVCTRLQueryAttribute;
decltype(&::XNVCTRLQueryTargetStringAttribute) XNVCTRLQueryTargetStringAttribute;
decltype(&::XNVCTRLQueryTargetAttribute64) XNVCTRLQueryTargetAttribute64;
decltype(&::XNVCTRLQueryTargetCount) XNVCTRLQueryTargetCount;
private:
void CleanUp(bool unload);

@ -240,19 +240,6 @@ bool libnvml_loader::Load(const std::string& library_name) {
return false;
}
#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)
nvmlDeviceGetFanSpeed =
reinterpret_cast<decltype(this->nvmlDeviceGetFanSpeed)>(
dlsym(library_, "nvmlDeviceGetFanSpeed"));
#endif
#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)
nvmlDeviceGetFanSpeed = &::nvmlDeviceGetFanSpeed;
#endif
if (!nvmlDeviceGetFanSpeed) {
CleanUp(true);
return false;
}
loaded_ = true;
return true;
}
@ -277,5 +264,4 @@ void libnvml_loader::CleanUp(bool unload) {
nvmlDeviceGetCurrentClocksThrottleReasons = NULL;
nvmlUnitGetFanSpeedInfo = NULL;
nvmlUnitGetHandleByIndex = NULL;
nvmlDeviceGetFanSpeed = NULL;
}

@ -40,8 +40,7 @@ class libnvml_loader {
decltype(&::nvmlDeviceGetCurrentClocksThrottleReasons) nvmlDeviceGetCurrentClocksThrottleReasons;
decltype(&::nvmlUnitGetFanSpeedInfo) nvmlUnitGetFanSpeedInfo;
decltype(&::nvmlUnitGetHandleByIndex) nvmlUnitGetHandleByIndex;
decltype(&::nvmlDeviceGetFanSpeed) nvmlDeviceGetFanSpeed;
private:
void CleanUp(bool unload);

@ -37,14 +37,6 @@ bool libx11_loader::Load(const std::string& library_name) {
return false;
}
XDefaultScreen =
reinterpret_cast<decltype(this->XDefaultScreen)>(
dlsym(library_, "XDefaultScreen"));
if (!XDefaultScreen) {
CleanUp(true);
return false;
}
XQueryKeymap =
reinterpret_cast<decltype(this->XQueryKeymap)>(
dlsym(library_, "XQueryKeymap"));

@ -16,7 +16,6 @@ class libx11_loader {
decltype(&::XOpenDisplay) XOpenDisplay;
decltype(&::XCloseDisplay) XCloseDisplay;
decltype(&::XDefaultScreen) XDefaultScreen;
decltype(&::XQueryKeymap) XQueryKeymap;
decltype(&::XKeysymToKeycode) XKeysymToKeycode;
decltype(&::XStringToKeysym) XStringToKeysym;

@ -1,7 +1,6 @@
#include <sstream>
#include <iomanip>
#include <array>
#include <algorithm>
#include <spdlog/spdlog.h>
#include "logging.h"
#include "overlay.h"
@ -27,8 +26,7 @@ string exec(string command) {
#endif
std::array<char, 128> buffer;
std::string result;
auto deleter = [](FILE* ptr){ pclose(ptr); };
std::unique_ptr<FILE, decltype(deleter)> pipe(popen(command.c_str(), "r"), deleter);
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
if (!pipe) {
return "popen failed!";
}
@ -72,24 +70,12 @@ static void writeSummary(string filename){
SPDLOG_DEBUG("Writing summary log file [{}]", filename);
std::ofstream out(filename, ios::out | ios::app);
if (out){
out << "0.1% Min FPS," << "1% Min FPS," << "97% Percentile FPS," << "Average FPS," << "GPU Load," << "CPU Load," << "Average Frame Time," << "Average GPU Temp," << "Average CPU Temp," << "Average VRAM Used," << "Average RAM Used," << "Average Swap Used," << "Peak GPU Load," << "Peak CPU Load," << "Peak GPU Temp," << "Peak CPU Temp," << "Peak VRAM Used," << "Peak RAM Used," << "Peak Swap Used" << "\n";
out << "0.1% Min FPS," << "1% Min FPS," << "97% Percentile FPS," << "Average FPS," << "GPU Load," << "CPU Load" << "\n";
std::vector<logData> sorted = logArray;
std::sort(sorted.begin(), sorted.end(), compareByFps);
float total = 0.0f;
float total_gpu = 0.0f;
float total_cpu = 0.0f;
int total_gpu_temp = 0.0f;
int total_cpu_temp = 0.0f;
float total_vram = 0.0f;
float total_ram = 0.0f;
float total_swap = 0.0f;
int peak_gpu = 0.0f;
float peak_cpu = 0.0f;
int peak_gpu_temp = 0.0f;
int peak_cpu_temp = 0.0f;
float peak_vram = 0.0f;
float peak_ram = 0.0f;
float peak_swap = 0.0f;
float total_gpu = 0.0f;
float result;
float percents[2] = {0.001, 0.01};
for (auto percent : percents){
@ -104,66 +90,21 @@ static void writeSummary(string filename){
// 97th percentile
result = sorted.empty() ? 0.0f : 1000 / sorted[floor(0.97 * (sorted.size() - 1))].frametime;
out << fixed << setprecision(1) << result << ",";
// avg + peak
// avg
total = 0;
for (auto input : sorted){
total = total + input.frametime;
total_gpu = total_gpu + input.gpu_load;
total_cpu = total_cpu + input.cpu_load;
total_gpu_temp = total_gpu_temp + input.gpu_temp;
total_cpu_temp = total_cpu_temp + input.cpu_temp;
total_vram = total_vram + input.gpu_vram_used;
total_ram = total_ram + input.ram_used;
total_swap = total_swap + input.swap_used;
peak_gpu = std::max(peak_gpu, input.gpu_load);
peak_cpu = std::max(peak_cpu, input.cpu_load);
peak_gpu_temp = std::max(peak_gpu_temp, input.gpu_temp);
peak_cpu_temp = std::max(peak_cpu_temp, input.cpu_temp);
peak_vram = std::max(peak_vram, input.gpu_vram_used);
peak_ram = std::max(peak_ram, input.ram_used);
peak_swap = std::max(peak_swap, input.swap_used);
total_gpu = total_gpu + input.gpu_load;
}
// Average FPS
result = 1000 / (total / sorted.size());
out << fixed << setprecision(1) << result << ",";
// GPU Load (Average)
// GPU
result = total_gpu / sorted.size();
out << result << ",";
// CPU Load (Average)
// CPU
result = total_cpu / sorted.size();
out << result << ",";
// Average Frame Time
result = total / sorted.size();
out << result << ",";
// Average GPU Temp
result = total_gpu_temp / sorted.size();
out << result << ",";
// Average CPU Temp
result = total_cpu_temp / sorted.size();
out << result << ",";
// Average VRAM Used
result = total_vram / sorted.size();
out << result << ",";
// Average RAM Used
result = total_ram / sorted.size();
out << result << ",";
// Average Swap Used
result = total_swap / sorted.size();
out << result << ",";
// Peak GPU Load
out << peak_gpu << ",";
// Peak CPU Load
out << peak_cpu << ",";
// Peak GPU Temp
out << peak_gpu_temp << ",";
// Peak CPU Temp
out << peak_cpu_temp << ",";
// Peak VRAM Used
out << peak_vram << ",";
// Peak RAM Used
out << peak_ram << ",";
// Peak Swap Used
out << peak_swap;
out << result;
} else {
SPDLOG_ERROR("Failed to write log file");
}
@ -184,8 +125,7 @@ static void writeFileHeaders(ofstream& out){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_log_versioning])
out << "--------------------FRAME METRICS--------------------" << endl;
out << "fps," << "frametime," << "cpu_load," << "gpu_load," << "cpu_temp," << "gpu_temp," << "gpu_core_clock," << "gpu_mem_clock," << "gpu_vram_used," << "gpu_power," << "ram_used," << "swap_used," << "process_rss," << "elapsed" << endl;
out << "fps," << "frametime," << "cpu_load," << "gpu_load," << "cpu_temp," << "gpu_temp," << "gpu_core_clock," << "gpu_mem_clock," << "gpu_vram_used," << "gpu_power," << "ram_used," << "elapsed" << endl;
}
void Logger::writeToFile(){
@ -207,8 +147,6 @@ void Logger::writeToFile(){
output_file << logArray.back().gpu_vram_used << ",";
output_file << logArray.back().gpu_power << ",";
output_file << logArray.back().ram_used << ",";
output_file << logArray.back().swap_used << ",";
output_file << logArray.back().process_rss << ",";
output_file << std::chrono::duration_cast<std::chrono::nanoseconds>(logArray.back().previous).count() << "\n";
output_file.flush();
} else {
@ -331,9 +269,7 @@ void Logger::calculate_benchmark_data(){
for (auto& point : m_log_array)
sorted.push_back(point.frametime);
std::sort(sorted.begin(), sorted.end(), [](float a, float b) {
return a > b;
});
std::sort(sorted.begin(), sorted.end());
benchmark.percentile_data.clear();
benchmark.total = 0.f;
@ -362,14 +298,14 @@ void Logger::calculate_benchmark_data(){
benchmark.percentile_data.push_back({percentile, (1000 / result)});
}
string label;
float mins[2] = {0.01f, 0.001f};
float mins[2] = {0.01f, 0.001f}, total;
for (auto percent : mins){
if (sorted.empty())
continue;
size_t percentile_pos = sorted.size() * percent;
percentile_pos = std::min(percentile_pos, sorted.size() - 1);
float result = 1000 / sorted[percentile_pos];
total = 0;
size_t idx = ceil(sorted.size() * percent);
for (size_t i = 0; i < idx; i++){
total = total + sorted[i];
}
result = 1000 / (total / idx);
if (percent == 0.001f)
label = "0.1%";

@ -25,8 +25,6 @@ struct logData{
int gpu_power;
float gpu_vram_used;
float ram_used;
float swap_used;
float process_rss;
Clock::duration previous;
};
@ -60,7 +58,6 @@ public:
std::string output_folder;
const int64_t log_interval;
const int64_t log_duration;
bool autostart_init = false;
private:
std::vector<logData> m_log_array;

@ -8,7 +8,5 @@
dlsym;
mangohud_find_glx_ptr;
mangohud_find_egl_ptr;
wl_display_connect;
wl_display_connect_to_fd;
local: *;
};

@ -5,7 +5,7 @@
#include <stdio.h>
#include <thread>
extern float memused, memmax, swapused, swapmax, rss;
extern float memused, memmax, swapused, swapmax;
struct memory_information {
/* memory information in kilobytes */

@ -1,28 +1,12 @@
glslang = find_program('glslang', 'glslangValidator')
if get_option('dynamic_string_tokens')
ld_prefix = get_option('prefix') + '/\$LIB/'
else
ld_prefix = join_paths(get_option('prefix') ,get_option('libdir')) + '/'
endif
# Needs prefix for configure_file()
if get_option('append_libdir_mangohud')
libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'), 'mangohud')
ld_libdir_mangohud = ld_prefix + 'mangohud/'
ld_libdir_mangohud = get_option('prefix') + '/\$LIB/mangohud/'
else
libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'))
ld_libdir_mangohud = ld_prefix
endif
git = find_program('git', required: false)
if git.found()
git_describe = run_command([git, 'describe', '--tags', '--dirty=+'], check: false)
endif
if git.found() and git_describe.returncode() == 0
describe_ver = git_describe.stdout().strip()
else
describe_ver = meson.project_version()
ld_libdir_mangohud = get_option('prefix') + '/\$LIB/'
endif
conf_data = configuration_data()
@ -30,7 +14,7 @@ conf_data = configuration_data()
conf_data.set('ld_libdir_mangohud_abs', libdir_mangohud)
conf_data.set('ld_libdir_mangohud', ld_libdir_mangohud)
conf_data.set('cpu_family', host_machine.cpu_family())
conf_data.set('version', describe_ver)
conf_data.set('version', run_command(['git', 'describe', '--tags', '--dirty=+']).stdout().strip())
overlay_shaders = [
'overlay.frag',
@ -59,7 +43,7 @@ vklayer_files = files(
'config.cpp',
'gpu.cpp',
'blacklist.cpp',
'file_utils.cpp'
'file_utils.cpp',
)
opengl_files = []
@ -88,12 +72,9 @@ if is_unixy
'pci_ids.cpp',
'battery.cpp',
'control.cpp',
'device.cpp',
'gamepad.cpp',
'amdgpu.cpp',
'intel.cpp',
'msm.cpp',
'net.cpp',
'shell.cpp'
'intel.cpp'
)
opengl_files = files(
@ -145,20 +126,11 @@ if is_unixy
'loaders/loader_x11.cpp',
'shared_x11.cpp',
)
endif
opengl_files += files(
'loaders/loader_glx.cpp',
'gl/inject_glx.cpp',
)
if get_option('with_wayland').enabled()
pre_args += '-DHAVE_WAYLAND'
vklayer_files += files(
'wayland_hook.cpp',
'wayland_keybinds.cpp'
)
endif
if dbus_dep.found() and get_option('with_dbus').enabled()
@ -202,8 +174,7 @@ mangohud_static_lib = static_library(
dep_pthread,
dep_vulkan,
windows_deps,
json_dep,
implot_dep],
json_dep],
include_directories : [inc_common],
link_args : link_args,
install_dir : libdir_mangohud,
@ -244,11 +215,9 @@ mangohud_opengl_shared_lib = shared_library(
dep_pthread,
dep_vulkan,
windows_deps,
json_dep,
implot_dep],
json_dep],
include_directories : [inc_common],
link_args : link_args,
link_with: mangohud_static_lib,
install_dir : libdir_mangohud,
install: true
)
@ -271,16 +240,12 @@ if is_unixy
dependencies : [dep_dl],
include_directories : [inc_common],
link_args : link_args,
link_with: mangohud_static_lib,
install_dir : libdir_mangohud,
install : true
)
endif
if get_option('mangoapp')
if not get_option('with_x11').enabled()
error('mangoapp also needs \'with_x11\'')
endif
pre_args += '-DIMGUI_IMPL_OPENGL_LOADER_GLEW'
pre_args += '-DMANGOAPP'
mangoapp = executable(
@ -300,15 +265,11 @@ if get_option('mangoapp')
dependencies : [
dearimgui_dep,
dep_dl,
dep_vulkan,
spdlog_dep,
dbus_dep,
dep_x11,
dep_wayland_client,
glfw3_dep,
json_dep,
glew_dep,
implot_dep
],
include_directories : [inc_common],
install_tag : 'mangoapp',

@ -1,79 +0,0 @@
#include <filesystem.h>
#include <mesa/util/os_time.h>
#include <inttypes.h>
#include "msm.h"
std::unique_ptr<MSM> msm;
namespace fs = ghc::filesystem;
uint64_t MSM::get_gpu_time() {
char line[256];
uint64_t total_val = 0;
for (auto fd : fdinfo) {
rewind(fd);
fflush(fd);
uint64_t val = 0;
while (fgets(line, sizeof(line), fd)){
if (sscanf(line, "drm-engine-gpu: %" SCNu64 " ns", &val) == 1) {
total_val += val;
break;
}
}
}
return total_val;
}
void MSM::find_fd() {
DIR* dir = opendir("/proc/self/fdinfo");
if (!dir) {
perror("Failed to open directory");
}
for (const auto& entry : fs::directory_iterator("/proc/self/fdinfo")){
FILE* file = fopen(entry.path().string().c_str(), "r");
if (!file) continue;
char line[256];
bool found_driver = false;
while (fgets(line, sizeof(line), file)) {
if (strstr(line, "msm") != NULL)
found_driver = true;
if (found_driver) {
if(strstr(line, "drm-engine-gpu")) {
fdinfo.push_back(file);
break;
}
}
}
if (!found_driver)
fclose(file);
}
closedir(dir);
}
void MSM::get_fdinfo() {
static uint64_t previous_gpu_time, previous_time, now, gpu_time_now;
gpu_time_now = get_gpu_time();
now = os_time_get_nano();
if (previous_time && previous_gpu_time && gpu_time_now > previous_gpu_time){
float time_since_last = now - previous_time;
float gpu_since_last = gpu_time_now - previous_gpu_time;
auto result = int((gpu_since_last / time_since_last) * 100);
if (result > 100)
result = 100;
gpu_info_msm.load = result;
previous_gpu_time = gpu_time_now;
previous_time = now;
} else {
previous_gpu_time = gpu_time_now;
previous_time = now;
}
}

@ -1,34 +0,0 @@
#include <memory>
#include <vector>
#include "gpu.h"
class MSM {
private:
struct gpuInfo gpu_info_msm {};
std::vector<FILE*> fdinfo;
void find_fd();
uint64_t get_gpu_time();
void get_fdinfo();
public:
MSM() {
find_fd();
}
~MSM() {
for (size_t i = 0; i < fdinfo.size(); i++) {
fclose(fdinfo[i]);
}
fdinfo.clear();
}
void update() {
if (!fdinfo.empty())
get_fdinfo();
gpu_info = gpu_info_msm;
}
};
extern std::unique_ptr<MSM> msm;

@ -1,58 +0,0 @@
#include "net.h"
#include "hud_elements.h"
Net::Net() {
should_reset = false;
fs::path net_dir(NETDIR);
if (fs::exists(net_dir) && fs::is_directory(net_dir)) {
for (const auto& entry : fs::directory_iterator(net_dir)) {
if (fs::is_directory(entry.status())) {
auto val = entry.path().filename().string();
if (val == "lo")
continue;
if (!HUDElements.params->network.empty() && HUDElements.params->network.front() == "1") {
interfaces.push_back({entry.path().filename().string(), 0, 0});
} else if (!HUDElements.params->network.empty()){
auto it = std::find(HUDElements.params->network.begin(), HUDElements.params->network.end(), val);
if (it != HUDElements.params->network.end())
interfaces.push_back({entry.path().filename().string(), 0, 0});
}
}
}
}
if (interfaces.empty())
SPDLOG_ERROR("Network: couldn't find any interfaces");
}
void Net::update() {
if (!interfaces.empty()) {
for (auto& iface : interfaces) {
// path to tx_bytes and rx_bytes
std::string txfile = (NETDIR + iface.name + TXFILE);
std::string rxfile = (NETDIR + iface.name + RXFILE);
// amount of bytes at previous update
uint64_t prevTx = iface.txBytes;
uint64_t prevRx = iface.rxBytes;
// current amount of bytes
iface.txBytes = std::stoll(read_line(txfile));
iface.rxBytes = std::stoll(read_line(rxfile));
auto now = std::chrono::steady_clock::now();
// calculate the bytes per second since last update
iface.txBps = calculateThroughput(iface.txBytes, prevTx, iface.previousTime, now);
iface.rxBps = calculateThroughput(iface.rxBytes, prevRx, iface.previousTime, now);
iface.previousTime = now;
}
}
}
uint64_t Net::calculateThroughput(long long currentBytes, long long previousBytes,
std::chrono::steady_clock::time_point previousTime,
std::chrono::steady_clock::time_point currentTime) {
std::chrono::duration<double> elapsed = (currentTime - previousTime);
return static_cast<long long>((currentBytes - previousBytes) / elapsed.count());
}

@ -1,46 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <stdint.h>
#include "filesystem.h"
#include "file_utils.h"
#include <spdlog/spdlog.h>
#include <iostream>
namespace fs = ghc::filesystem;
#ifndef NETDIR
#define NETDIR "/sys/class/net/"
#endif
#ifndef TXFILE
#define TXFILE "/statistics/tx_bytes"
#endif
#ifndef RXFILE
#define RXFILE "/statistics/rx_bytes"
#endif
class Net {
public:
bool should_reset = false;
struct networkInterface {
std::string name;
uint64_t txBytes;
uint64_t rxBytes;
uint64_t txBps;
uint64_t rxBps;
std::chrono::steady_clock::time_point previousTime;
};
Net();
void update();
std::vector<networkInterface> interfaces = {};
private:
uint64_t calculateThroughput(long long currentBytes, long long previousBytes,
std::chrono::steady_clock::time_point previousTime,
std::chrono::steady_clock::time_point currentTime);
};
extern std::unique_ptr<Net> net;

@ -16,7 +16,6 @@ static std::unique_ptr<Display, std::function<void(Display*)>> display;
struct nvctrlInfo nvctrl_info;
bool nvctrlSuccess = false;
int num_coolers = 0;
static bool find_nv_x11(libnvctrl_loader& nvctrl, Display*& dpy)
{
@ -26,8 +25,7 @@ static bool find_nv_x11(libnvctrl_loader& nvctrl, Display*& dpy)
snprintf(buf, sizeof(buf), ":%d", i);
Display *d = libx11->XOpenDisplay(buf);
if (d) {
int s = libx11->XDefaultScreen(d);
if (nvctrl.XNVCTRLIsNvScreen(d, s)) {
if (nvctrl.XNVCTRLIsNvScreen(d, i)) {
dpy = d;
SPDLOG_DEBUG("XNVCtrl is using display {}", buf);
return true;
@ -45,7 +43,7 @@ bool checkXNVCtrl()
auto& nvctrl = get_libnvctrl_loader();
if (!nvctrl.IsLoaded()) {
SPDLOG_DEBUG("XNVCtrl loader failed to load");
SPDLOG_ERROR("XNVCtrl loader failed to load");
return false;
}
@ -73,11 +71,6 @@ bool checkXNVCtrl()
&pci_id);
deviceID = (pci_id & 0xFFFF);
// get number of coolers at init
nvctrl.XNVCTRLQueryTargetCount(display.get(),
NV_CTRL_TARGET_TYPE_COOLER,
&num_coolers);
return true;
}
@ -169,15 +162,13 @@ void getNvctrlInfo(){
}
int64_t getNvctrlFanSpeed(){
auto& nvctrl = get_libnvctrl_loader();
int64_t fan_speed = 0;
if (num_coolers >= 1) {
auto& nvctrl = get_libnvctrl_loader();
nvctrl.XNVCTRLQueryTargetAttribute64(display.get(),
NV_CTRL_TARGET_TYPE_COOLER,
0,
0,
NV_CTRL_THERMAL_COOLER_SPEED,
&fan_speed);
}
nvctrl.XNVCTRLQueryTargetAttribute64(display.get(),
NV_CTRL_TARGET_TYPE_COOLER,
0,
0,
NV_CTRL_THERMAL_COOLER_SPEED,
&fan_speed);
return fan_speed;
}

@ -5,7 +5,6 @@
#include "overlay.h"
#include "overlay_params.h"
#include "nvctrl.h"
#include "logging.h"
nvmlReturn_t result;
nvmlDevice_t nvidiaDevice;
@ -15,6 +14,7 @@ unsigned int nvidiaTemp = 0, nvidiaCoreClock = 0, nvidiaMemClock = 0, nvidiaPowe
unsigned long long nvml_throttle_reasons;
struct nvmlUtilization_st nvidiaUtilization;
struct nvmlMemory_st nvidiaMemory {};
struct nvmlUnitFanSpeeds_st nvidiaFanSpeeds {};
struct nvmlUnit_st* nvidiaUnit {};
bool checkNVML(const char* pciBusId){
@ -53,23 +53,15 @@ bool getNVMLInfo(const struct overlay_params& params){
nvmlReturn_t response;
auto& nvml = get_libnvml_loader();
response = nvml.nvmlDeviceGetUtilizationRates(nvidiaDevice, &nvidiaUtilization);
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_temp] || logger->is_active())
nvml.nvmlDeviceGetTemperature(nvidiaDevice, NVML_TEMPERATURE_GPU, &nvidiaTemp);
if (params.enabled[OVERLAY_PARAM_ENABLED_vram] || logger->is_active())
nvml.nvmlDeviceGetMemoryInfo(nvidiaDevice, &nvidiaMemory);
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock] || logger->is_active())
nvml.nvmlDeviceGetClockInfo(nvidiaDevice, NVML_CLOCK_GRAPHICS, &nvidiaCoreClock);
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock] || logger->is_active())
nvml.nvmlDeviceGetClockInfo(nvidiaDevice, NVML_CLOCK_MEM, &nvidiaMemClock);
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_power] || logger->is_active())
nvml.nvmlDeviceGetPowerUsage(nvidiaDevice, &nvidiaPowerUsage);
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);
nvml.nvmlDeviceGetPowerUsage(nvidiaDevice, &nvidiaPowerUsage);
deviceID = nvidiaPciInfo.pciDeviceId >> 16;
if (params.enabled[OVERLAY_PARAM_ENABLED_throttling_status])
nvml.nvmlDeviceGetCurrentClocksThrottleReasons(nvidiaDevice, &nvml_throttle_reasons);
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_fan] || logger->is_active())
nvml.nvmlDeviceGetFanSpeed(nvidiaDevice, &nvidiaFanSpeed);
if (response == NVML_ERROR_NOT_SUPPORTED) {
if (nvmlSuccess)
SPDLOG_ERROR("nvmlDeviceGetUtilizationRates failed");

@ -17,16 +17,13 @@
#include "fcat.h"
#include "mesa/util/macros.h"
#include "battery.h"
#include "device.h"
#include "gamepad.h"
#include "string_utils.h"
#include "file_utils.h"
#include "pci_ids.h"
#include "iostats.h"
#include "amdgpu.h"
#include "fps_metrics.h"
#include "intel.h"
#include "msm.h"
#include "net.h"
#ifdef __linux__
#include <libgen.h>
@ -75,7 +72,7 @@ void init_spdlog()
SPDLOG_ERROR("{}", ex.what());
}
}
#ifdef DEBUG
#ifndef NDEBUG
spdlog::set_level(spdlog::level::level_enum::debug);
#endif
spdlog::cfg::load_env_levels();
@ -91,12 +88,6 @@ void init_spdlog()
spdlog::set_level(spdlog::level::from_str(log_level));
}
}
#ifndef DEBUG
} else {
std::string log_level = "err";
transform(log_level.begin(), log_level.end(), log_level.begin(), ::tolower);
spdlog::set_level(spdlog::level::from_str(log_level));
#endif
}
}
@ -132,25 +123,23 @@ void update_hw_info(const struct overlay_params& params, uint32_t vendorID)
getAmdGpuInfo();
#ifdef __linux__
if (gpu_metrics_exists)
amdgpu_get_metrics(deviceID);
amdgpu_get_metrics();
#endif
if (vendorID == 0x10de)
getNvidiaGpuInfo(params);
#ifdef __linux__
if (vendorID== 0x8086)
if (intel) intel->update();
if (vendorID == 0x5143)
if (msm) msm->update();
getIntelGpuInfo();
#endif
}
#ifdef __linux__
if (params.enabled[OVERLAY_PARAM_ENABLED_battery])
Battery_Stats.update();
if (!params.device_battery.empty()) {
device_update(params);
if (device_found) {
device_info();
if (params.enabled[OVERLAY_PARAM_ENABLED_gamepad_battery]) {
gamepad_update();
if (gamepad_found) {
gamepad_info();
}
}
if (params.enabled[OVERLAY_PARAM_ENABLED_ram] || params.enabled[OVERLAY_PARAM_ENABLED_swap] || logger->is_active())
@ -169,8 +158,6 @@ void update_hw_info(const struct overlay_params& params, uint32_t vendorID)
currentLogData.gpu_power = gpu_info.powerUsage;
#ifdef __linux__
currentLogData.ram_used = memused;
currentLogData.swap_used = swapused;
currentLogData.process_rss = proc_mem.resident / float((2 << 29)); // GiB, consistent w/ other mem stats
#endif
currentLogData.cpu_load = cpuStats.GetCPUDataTotal().percent;
@ -252,27 +239,17 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru
if (sw_stats.last_present_time) {
sw_stats.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing] =
frametime_ns;
frametime_data.push_back(frametime_ms);
frametime_data.erase(frametime_data.begin());
frametime_data[f_idx] = frametime_ms;
}
#ifdef __linux__
if (throttling)
throttling->update();
#endif
frametime = frametime_ms;
fps = double(1000 / frametime_ms);
if (fpsmetrics) fpsmetrics->update(now, fps);
if (elapsed >= params.fps_sampling_period) {
if (!hw_update_thread)
hw_update_thread = std::make_unique<hw_info_updater>();
hw_update_thread->update(&params, vendorID);
if (fpsmetrics) fpsmetrics->update_thread();
#ifdef __linux__
if (HUDElements.net) HUDElements.net->update();
#endif
sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed;
if (params.enabled[OVERLAY_PARAM_ENABLED_time]) {
@ -282,13 +259,6 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru
sw_stats.time = time.str();
}
if (params.autostart_log && logger && !logger->autostart_init) {
if ((std::chrono::steady_clock::now() - HUDElements.overlay_start) > std::chrono::seconds(params.autostart_log)){
logger->start_logging();
logger->autostart_init = true;
}
}
sw_stats.n_frames_since_update = 0;
sw_stats.last_fps_update = now;
@ -417,7 +387,9 @@ void RenderOutlinedText(const char* text, ImU32 textColor) {
float outlineThickness = HUDElements.params->text_outline_thickness;
ImVec2 textSize = ImGui::CalcTextSize(text);
ImU32 outlineColor = ImGui::ColorConvertFloat4ToU32(HUDElements.colors.text_outline);
ImVec4 colorVec4 = ImGui::ColorConvertU32ToFloat4(HUDElements.params->text_outline_color);
colorVec4.w = HUDElements.params->alpha;
ImU32 outlineColor = ImGui::ColorConvertFloat4ToU32(colorVec4);
ImVec2 pos = window->DC.CursorPos;
ImDrawList* drawList = ImGui::GetWindowDrawList();
@ -608,9 +580,9 @@ static void render_benchmark(swapchain_stats& data, const struct overlay_params&
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 0.0, 0.0, alpha / params.background_alpha));
ImGui::Dummy(ImVec2(0.0f, 8.0f));
if (params.enabled[OVERLAY_PARAM_ENABLED_histogram])
ImGui::PlotHistogram("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50));
ImGui::PlotHistogram("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvailWidth(), 50));
else
ImGui::PlotLines("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50));
ImGui::PlotLines("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvailWidth(), 50));
ImGui::PopStyleColor(2);
ImGui::End();
}
@ -666,10 +638,6 @@ void horizontal_separator(struct overlay_params& params) {
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan)
{
{
std::unique_lock<std::mutex> lock(config_mtx);
config_cv.wait(lock, []{ return config_ready; });
}
// data.engine = EngineTypes::GAMESCOPE;
HUDElements.sw_stats = &data; HUDElements.params = &params;
HUDElements.is_vulkan = is_vulkan;
@ -694,16 +662,18 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
if(params.enabled[OVERLAY_PARAM_ENABLED_horizontal])
table_flags = ImGuiTableFlags_NoClip | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
if (!params.no_display && !steam_focused && params.table_columns){
if (!params.no_display && !steam_focused){
ImGui::Begin("Main", &gui_open, ImGuiWindowFlags_NoDecoration);
if (ImGui::BeginTable("hud", params.table_columns, table_flags )) {
HUDElements.place = 0;
for (auto& func : HUDElements.ordered_functions){
if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && func.name != "exec")
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(-3,-3));
if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && func.first != HudElements::_exec)
ImGui::TableNextRow();
func.run();
func.first();
HUDElements.place += 1;
if(!HUDElements.ordered_functions.empty() && params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && HUDElements.ordered_functions.size() != (size_t)HUDElements.place)
ImGui::PopStyleVar();
if(!HUDElements.ordered_functions.empty() && params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && func != HUDElements.ordered_functions.back())
horizontal_separator(params);
}
@ -711,7 +681,7 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
if (HUDElements.table_columns_count > 0 && HUDElements.table_columns_count < 65 )
params.table_columns = HUDElements.table_columns_count;
if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) {
float content_width = ImGui::GetContentRegionAvail().x - (params.table_columns * 64);
float content_width = ImGui::GetContentRegionAvailWidth() - (params.table_columns * 64);
window_size = ImVec2(content_width, params.height);
}
}
@ -840,24 +810,10 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
path = drm + dir;
drm_dev = dir;
SPDLOG_DEBUG("Intel: using drm device {}", drm_dev);
intel = std::make_unique<Intel>();
break;
}
}
if (vendorID == 0x5143) {
auto dirs = ls(drm.c_str(), "card");
for (auto& dir : dirs) {
if (dir.find("-") != std::string::npos) {
continue; // filter display adapters
}
path = drm + dir;
drm_dev = dir;
SPDLOG_DEBUG("msm: using drm device {}", drm_dev);
msm = std::make_unique<MSM>();
}
}
if (vendorID == 0x1002
|| gpu.find("Radeon") != std::string::npos
|| gpu.find("AMD") != std::string::npos) {
@ -909,10 +865,8 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
const std::string device_path = path + "/device";
const std::string gpu_metrics_path = device_path + "/gpu_metrics";
if (amdgpu_verify_metrics(gpu_metrics_path)) {
gpu_info.fan_rpm = true;
gpu_metrics_exists = true;
metrics_path = gpu_metrics_path;
throttling = std::make_unique<Throttling>();
SPDLOG_DEBUG("Using gpu_metrics of {}", gpu_metrics_path);
}
@ -938,28 +892,26 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
if (!amdgpu.gpu_voltage_soc)
amdgpu.gpu_voltage_soc = fopen((hwmon_path + dir + "/in0_input").c_str(), "r");
}
}
if (!metrics_path.empty())
break;
// The card output nodes - cardX-output, will point to the card node
// As such the actual metrics nodes will be missing.
amdgpu.busy = fopen((device_path + "/gpu_busy_percent").c_str(), "r");
if (!amdgpu.busy)
continue;
SPDLOG_DEBUG("using amdgpu path: {}", device_path);
if (!metrics_path.empty())
break;
for (const auto& dir : dirs) {
if (!amdgpu.memory_clock)
amdgpu.memory_clock = fopen((hwmon_path + dir + "/freq2_input").c_str(), "r");
if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((hwmon_path + dir + "/power1_average").c_str(), "r");
if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((hwmon_path + dir + "/power1_input").c_str(), "r");
if (!amdgpu.fan)
amdgpu.fan = fopen((hwmon_path + dir + "/fan1_input").c_str(), "r");
}
// The card output nodes - cardX-output, will point to the card node
// As such the actual metrics nodes will be missing.
amdgpu.busy = fopen((device_path + "/gpu_busy_percent").c_str(), "r");
if (!amdgpu.busy)
continue;
SPDLOG_DEBUG("using amdgpu path: {}", device_path);
for (const auto& dir : dirs) {
if (!amdgpu.memory_clock)
amdgpu.memory_clock = fopen((hwmon_path + dir + "/freq2_input").c_str(), "r");
if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((hwmon_path + dir + "/power1_average").c_str(), "r");
if (!amdgpu.fan)
amdgpu.fan = fopen((hwmon_path + dir + "/fan1_input").c_str(), "r");
}
break;
}

@ -91,7 +91,6 @@ extern double min_frametime, max_frametime;
extern bool steam_focused;
extern int fan_speed;
extern int current_preset;
extern std::vector<float> frametime_data;
void init_spdlog();
void overlay_new_frame(const struct overlay_params& params);

@ -14,7 +14,6 @@
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <cctype>
#include <array>
@ -38,12 +37,6 @@
#include "dbus_info.h"
#include "app/mangoapp.h"
#include "fps_metrics.h"
std::unique_ptr<fpsMetrics> fpsmetrics;
std::mutex config_mtx;
std::condition_variable config_cv;
bool config_ready = false;
#if __cplusplus >= 201703L
@ -111,8 +104,8 @@ parse_control(const char *str)
int ret = os_socket_listen_abstract(path.c_str(), 1);
if (ret < 0) {
SPDLOG_DEBUG("Couldn't create socket pipe at '{}'", path);
SPDLOG_DEBUG("ERROR: '{}'", strerror(errno));
SPDLOG_ERROR("Couldn't create socket pipe at '{}'", path);
SPDLOG_ERROR("ERROR: '{}'", strerror(errno));
return ret;
}
@ -159,7 +152,6 @@ parse_string_to_keysym_vec(const char *str)
#define parse_upload_logs parse_string_to_keysym_vec
#define parse_toggle_fps_limit parse_string_to_keysym_vec
#define parse_toggle_preset parse_string_to_keysym_vec
#define parse_reset_fps_metrics parse_string_to_keysym_vec
#else
#define parse_toggle_hud(x) {}
@ -170,7 +162,6 @@ parse_string_to_keysym_vec(const char *str)
#define parse_upload_logs(x) {}
#define parse_toggle_fps_limit(x) {}
#define parse_toggle_preset(x) {}
#define parse_reset_fps_metrics(x) {}
#endif
// NOTE: This is NOT defined as an OVERLAY_PARAM and will be called manually
@ -422,20 +413,6 @@ parse_gl_size_query(const char *str)
return GL_SIZE_DRAWABLE;
}
static std::vector<std::string>
parse_fps_metrics(const char *str){
std::vector<std::string> metrics;
auto tokens = str_tokenize(str);
for (auto& token : tokens) {
metrics.push_back(token);
}
fpsmetrics.release();
fpsmetrics = std::make_unique<fpsMetrics>(metrics);
return metrics;
}
#define parse_width(s) parse_unsigned(s)
#define parse_height(s) parse_unsigned(s)
#define parse_vsync(s) parse_unsigned(s)
@ -486,7 +463,6 @@ parse_fps_metrics(const char *str){
#define parse_text_color(s) parse_color(s)
#define parse_media_player_color(s) parse_color(s)
#define parse_wine_color(s) parse_color(s)
#define parse_network_color(s) parse_color(s)
#define parse_gpu_load_color(s) parse_load_color(s)
#define parse_cpu_load_color(s) parse_load_color(s)
#define parse_gpu_load_value(s) parse_load_value(s)
@ -501,8 +477,6 @@ parse_fps_metrics(const char *str){
#define parse_fsr_steam_sharpness(s) parse_float(s)
#define parse_text_outline_color(s) parse_color(s)
#define parse_text_outline_thickness(s) parse_float(s)
#define parse_device_battery(s) parse_str_tokenize(s)
#define parse_network(s) parse_str_tokenize(s)
static bool
parse_help(const char *str)
@ -576,116 +550,59 @@ const char *overlay_param_names[] = {
#undef OVERLAY_PARAM_CUSTOM
};
static void
initialize_preset(struct overlay_params *params)
{
if (params->options.find("preset") != params->options.end()) {
auto presets = parse_preset(params->options.find("preset")->second.c_str());
if (!presets.empty())
params->preset = presets;
}
current_preset = params->preset[0];
}
static void
set_parameters_from_options(struct overlay_params *params)
{
bool read_cfg = false;
if (params->options.find("read_cfg") != params->options.end() && params->options.find("read_cfg")->second != "0")
read_cfg = true;
if (params->options.find("full") != params->options.end() && params->options.find("full")->second != "0") {
#define OVERLAY_PARAM_BOOL(name) \
params->enabled[OVERLAY_PARAM_ENABLED_##name] = 1;
#define OVERLAY_PARAM_CUSTOM(name)
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
params->enabled[OVERLAY_PARAM_ENABLED_histogram] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_battery_icon] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_fcat] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_horizontal] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_log_versioning] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_exec_name] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_trilinear] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_bicubic] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_retro] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_debug] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_duration] = false;
params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false;
params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = read_cfg;
params->enabled[OVERLAY_PARAM_ENABLED_time_no_label] = false;
params->options.erase("full");
}
for (auto& it : params->options) {
#define OVERLAY_PARAM_BOOL(name) \
if (it.first == #name) { \
params->enabled[OVERLAY_PARAM_ENABLED_##name] = \
strtol(it.second.c_str(), NULL, 0); \
continue; \
}
#define OVERLAY_PARAM_CUSTOM(name) \
if (it.first == #name) { \
params->name = parse_##name(it.second.c_str()); \
continue; \
}
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
if (it.first == "preset") {
continue; // Handled above
}
SPDLOG_ERROR("Unknown option '{}'", it.first.c_str());
}
}
static void
parse_overlay_env(struct overlay_params *params,
const char *env, bool use_existing_preset)
const char *env)
{
const char *env_start = env;
uint32_t num;
char key[256], value[256];
while ((num = parse_string(env, key, value)) != 0) {
trim_char(key);
trim_char(value);
env += num;
if (!strcmp("preset", key)) {
if (!use_existing_preset) {
add_to_options(params, key, value);
initialize_preset(params);
}
break;
}
}
presets(current_preset, params);
env = env_start;
while ((num = parse_string(env, key, value)) != 0) {
trim_char(key);
trim_char(value);
env += num;
if (!strcmp("preset", key)) {
continue; // Avoid 'Unknown option' error
if (!strcmp("full", key)) {
bool read_cfg = params->enabled[OVERLAY_PARAM_ENABLED_read_cfg];
#define OVERLAY_PARAM_BOOL(name) \
params->enabled[OVERLAY_PARAM_ENABLED_##name] = 1;
#define OVERLAY_PARAM_CUSTOM(name)
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
params->enabled[OVERLAY_PARAM_ENABLED_histogram] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_gpu_load_change] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_cpu_load_change] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_fps_color_change] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_core_load_change] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_battery_icon] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = read_cfg;
params->enabled[OVERLAY_PARAM_ENABLED_fcat] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_horizontal] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch] = 1;
params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_log_versioning] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_exec_name] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_trilinear] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_bicubic] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_retro] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_debug] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false;
}
#define OVERLAY_PARAM_BOOL(name) \
if (!strcmp(#name, key)) { \
params->enabled[OVERLAY_PARAM_ENABLED_##name] = \
strtol(value, NULL, 0); \
add_to_options(params, key, value); \
continue; \
}
#define OVERLAY_PARAM_CUSTOM(name) \
if (!strcmp(#name, key)) { \
params->name = parse_##name(value); \
add_to_options(params, key, value); \
continue; \
}
@ -694,7 +611,6 @@ parse_overlay_env(struct overlay_params *params,
#undef OVERLAY_PARAM_CUSTOM
SPDLOG_ERROR("Unknown option '{}'", key);
}
set_parameters_from_options(params);
}
static void set_param_defaults(struct overlay_params *params){
@ -723,7 +639,8 @@ static void set_param_defaults(struct overlay_params *params){
params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] = true;
params->enabled[OVERLAY_PARAM_ENABLED_frametime] = true;
params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = false;
params->enabled[OVERLAY_PARAM_ENABLED_device_battery_icon] = false;
params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery] = false;
params->enabled[OVERLAY_PARAM_ENABLED_gamepad_battery_icon] = false;
params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = false;
params->enabled[OVERLAY_PARAM_ENABLED_fcat] = false;
params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch] = true;
@ -732,7 +649,6 @@ static void set_param_defaults(struct overlay_params *params){
params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = false;
params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = false;
params->enabled[OVERLAY_PARAM_ENABLED_duration] = false;
params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed] = false;
params->fps_sampling_period = 500000000; /* 500ms */
params->width = 0;
params->height = 140;
@ -758,7 +674,6 @@ static void set_param_defaults(struct overlay_params *params){
params->background_color = 0x020202;
params->text_color = 0xffffff;
params->media_player_color = 0xffffff;
params->network_color = 0xe07b85;
params->media_player_name = "";
params->font_scale = 1.0f;
params->wine_color = 0xeb5b5b;
@ -794,15 +709,11 @@ parse_overlay_config(struct overlay_params *params,
.preset = use_existing_preset ? params->preset : default_preset
};
set_param_defaults(params);
if (!use_existing_preset) {
current_preset = params->preset[0];
}
#ifdef HAVE_X11
params->toggle_hud = { XK_Shift_R, XK_F12 };
params->toggle_hud_position = { XK_Shift_R, XK_F11 };
params->toggle_preset = { XK_Shift_R, XK_F10 };
params->reset_fps_metrics = { XK_Shift_R, XK_F9};
params->toggle_fps_limit = { XK_Shift_L, XK_F1 };
params->toggle_logging = { XK_Shift_L, XK_F2 };
params->reload_cfg = { XK_Shift_L, XK_F4 };
@ -813,7 +724,6 @@ parse_overlay_config(struct overlay_params *params,
#ifdef _WIN32
params->toggle_hud = { VK_F12 };
params->toggle_preset = { VK_F10 };
params->reset_fps_metrics = { VK_F9};
params->toggle_fps_limit = { VK_F3 };
params->toggle_logging = { VK_F2 };
params->reload_cfg = { VK_F4 };
@ -833,31 +743,77 @@ parse_overlay_config(struct overlay_params *params,
HUDElements.ordered_functions.clear();
HUDElements.exec_list.clear();
params->options.clear();
HUDElements.options.clear();
// first pass with env var
if (env)
parse_overlay_env(params, env, use_existing_preset);
parse_overlay_env(params, env);
bool read_cfg = params->enabled[OVERLAY_PARAM_ENABLED_read_cfg];
bool env_contains_preset = params->options.find("preset") != params->options.end();
if (!env || read_cfg) {
// Get config options
parseConfigFile(*params);
if (!use_existing_preset && !env_contains_preset) {
initialize_preset(params);
if (!use_existing_preset) {
if (params->options.find("preset") != params->options.end()) {
auto presets = parse_preset(params->options.find("preset")->second.c_str());
if (!presets.empty())
params->preset = presets;
}
current_preset = params->preset[0];
}
// clear options since we don't want config options to appear first
params->options.clear();
HUDElements.options.clear();
// add preset options
presets(current_preset, params);
// potentially override preset options with config options
parseConfigFile(*params);
set_parameters_from_options(params);
if (params->options.find("full") != params->options.end() && params->options.find("full")->second != "0") {
#define OVERLAY_PARAM_BOOL(name) \
params->enabled[OVERLAY_PARAM_ENABLED_##name] = 1;
#define OVERLAY_PARAM_CUSTOM(name)
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
params->enabled[OVERLAY_PARAM_ENABLED_histogram] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_battery_icon] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_fcat] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_horizontal] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_log_versioning] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_exec_name] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_trilinear] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_bicubic] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_retro] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_debug] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = 0;
params->enabled[OVERLAY_PARAM_ENABLED_duration] = false;
params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false;
params->options.erase("full");
}
for (auto& it : params->options) {
#define OVERLAY_PARAM_BOOL(name) \
if (it.first == #name) { \
params->enabled[OVERLAY_PARAM_ENABLED_##name] = \
strtol(it.second.c_str(), NULL, 0); \
continue; \
}
#define OVERLAY_PARAM_CUSTOM(name) \
if (it.first == #name) { \
params->name = parse_##name(it.second.c_str()); \
continue; \
}
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
if (it.first == "preset") {
continue;
}
SPDLOG_ERROR("Unknown option '{}'", it.first.c_str());
}
}
// TODO decide what to do for legacy_layout=0
@ -865,7 +821,7 @@ parse_overlay_config(struct overlay_params *params,
if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] && env && read_cfg) {
// If passing legacy_layout=0 to MANGOHUD_CONFIG anyway then clear first pass' results
HUDElements.ordered_functions.clear();
parse_overlay_env(params, env, true);
parse_overlay_env(params, env);
}
// If fps_only param is enabled disable legacy_layout
@ -879,7 +835,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 *, 21> colors = {
&params->cpu_color,
&params->gpu_color,
&params->vram_color,
@ -901,8 +857,6 @@ parse_overlay_config(struct overlay_params *params,
&params->fps_color[0],
&params->fps_color[1],
&params->fps_color[2],
&params->text_outline_color,
&params->network_color,
};
for (auto color : colors){
@ -971,18 +925,11 @@ parse_overlay_config(struct overlay_params *params,
auto real_size = params->font_size * params->font_scale;
real_font_size = ImVec2(real_size, real_size / 2);
HUDElements.params = params;
for (const auto& option : HUDElements.options) {
SPDLOG_DEBUG("Param: '{}' = '{}'", option.first, option.second);
}
if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout]) {
HUDElements.legacy_elements();
if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout]){
HUDElements.legacy_elements();
} else {
HUDElements.ordered_functions.clear();
for (auto& option : HUDElements.options) {
for (auto& option : HUDElements.options)
HUDElements.sort_elements(option);
}
}
// Needs ImGui context but it is null here for OpenGL so just note it and update somewhere else
@ -997,6 +944,8 @@ parse_overlay_config(struct overlay_params *params,
logger->stop_logging();
}
logger = std::make_unique<Logger>(params);
if(params->autostart_log && !logger->is_active())
std::thread(autostart_log, params->autostart_log).detach();
#ifdef MANGOAPP
{
extern bool new_frame;
@ -1007,57 +956,35 @@ parse_overlay_config(struct overlay_params *params,
mangoapp_cv.notify_one();
g_fsrSharpness = params->fsr_steam_sharpness;
#endif
if (HUDElements.net)
HUDElements.net->should_reset = true;
{
std::lock_guard<std::mutex> lock(config_mtx);
config_ready = true;
config_cv.notify_one();
}
}
bool parse_preset_config(int preset, struct overlay_params *params){
const char *presets_file_env = getenv("MANGOHUD_PRESETSFILE");
const std::string data_dir = get_data_dir();
const std::string config_dir = get_config_dir();
std::string preset_path = presets_file_env ? presets_file_env : config_dir + "/MangoHud/" + "presets.conf";
std::string preset_path = config_dir + "/MangoHud/" + "presets.conf";
FILE *preset_file = fopen(preset_path.c_str(), "r");
char line[20];
char preset_string[20];
snprintf(preset_string, sizeof(preset_string), "[preset %d]", preset);
std::ifstream stream(preset_path);
stream.imbue(std::locale::classic());
if (!stream.good()) {
SPDLOG_DEBUG("Failed to read presets file: '{}'. Falling back to default presets", preset_path);
return false;
}
std::string line;
snprintf(preset_string, sizeof(preset_string), "[preset %d]\n", preset);
bool found_preset = false;
if (preset_file == NULL)
return false;
while (std::getline(stream, line)) {
trim(line);
if (line == "")
continue;
if (line == preset_string) {
while (fgets(line, sizeof(line), preset_file)){
if (strcmp(line, preset_string) == 0){
found_preset = true;
continue;
}
if (found_preset) {
if (line.front() == '[' && line.back() == ']')
if (found_preset){
if(strcmp(line, "preset") == 0 || line[0] == '\n' || line[0] == '\0')
break;
if (line == "inherit")
presets(preset, params, true);
parseConfigLine(line, params->options);
}
}
fclose(preset_file);
return found_preset;
}
@ -1066,10 +993,9 @@ void add_to_options(struct overlay_params *params, std::string option, std::stri
params->options[option] = value;
}
int i = 0;
void presets(int preset, struct overlay_params *params, bool inherit) {
if (!inherit && parse_preset_config(preset, params))
return;
void presets(int preset, struct overlay_params *params) {
if (parse_preset_config(preset, params))
return;
switch(preset) {
case 0:
@ -1084,7 +1010,6 @@ void presets(int preset, struct overlay_params *params, bool inherit) {
add_to_options(params, "fps", "1");
add_to_options(params, "fps_only", "1");
add_to_options(params, "frametime", "0");
add_to_options(params, "debug", "0");
break;
case 2:
@ -1105,7 +1030,6 @@ void presets(int preset, struct overlay_params *params, bool inherit) {
add_to_options(params, "cpu_power", "1");
add_to_options(params, "battery_watt", "1");
add_to_options(params, "battery_time", "1");
add_to_options(params, "debug", "0");
break;
case 3:
@ -1119,14 +1043,12 @@ void presets(int preset, struct overlay_params *params, bool inherit) {
add_to_options(params, "gpu_mem_clock", "1");
add_to_options(params, "gpu_core_clock", "1");
add_to_options(params, "battery", "1");
add_to_options(params, "hdr", "1");
add_to_options(params, "debug", "0");
break;
case 4:
add_to_options(params, "full", "1");
add_to_options(params, "throttling_status", "0");
add_to_options(params, "throttling_status_graph", "0");
add_to_options(params, "debug", "1");
add_to_options(params, "throttling_status", "1");
add_to_options(params, "io_read", "0");
add_to_options(params, "io_write", "0");
add_to_options(params, "arch", "0");
@ -1141,17 +1063,6 @@ void presets(int preset, struct overlay_params *params, bool inherit) {
add_to_options(params, "core_load_change", "0");
add_to_options(params, "cpu_load_change", "0");
add_to_options(params, "fps_color_change", "0");
add_to_options(params, "hdr", "1");
add_to_options(params, "refresh_rate", "1");
add_to_options(params, "media_player", "0");
add_to_options(params, "debug", "1");
add_to_options(params, "version", "0");
add_to_options(params, "frame_timing_detailed", "1");
add_to_options(params, "network", "1");
add_to_options(params, "present_mode", "0");
if ( deviceID == 0x1435 || deviceID == 0x163f )
add_to_options(params, "gpu_fan", "0");
break;
}

@ -6,8 +6,6 @@
#include <vector>
#include <unordered_map>
#include <cstdint>
#include <condition_variable>
#include <mutex>
#ifdef __cplusplus
extern "C" {
@ -83,11 +81,11 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(fsr) \
OVERLAY_PARAM_BOOL(mangoapp_steam) \
OVERLAY_PARAM_BOOL(debug) \
OVERLAY_PARAM_BOOL(device_battery_icon) \
OVERLAY_PARAM_BOOL(gamepad_battery) \
OVERLAY_PARAM_BOOL(gamepad_battery_icon) \
OVERLAY_PARAM_BOOL(hide_fsr_sharpness) \
OVERLAY_PARAM_BOOL(fan) \
OVERLAY_PARAM_BOOL(throttling_status) \
OVERLAY_PARAM_BOOL(throttling_status_graph) \
OVERLAY_PARAM_BOOL(fcat) \
OVERLAY_PARAM_BOOL(log_versioning) \
OVERLAY_PARAM_BOOL(horizontal) \
@ -107,13 +105,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(temp_fahrenheit) \
OVERLAY_PARAM_BOOL(dynamic_frame_timing) \
OVERLAY_PARAM_BOOL(duration) \
OVERLAY_PARAM_BOOL(inherit) \
OVERLAY_PARAM_BOOL(hdr) \
OVERLAY_PARAM_BOOL(refresh_rate) \
OVERLAY_PARAM_BOOL(frame_timing_detailed) \
OVERLAY_PARAM_BOOL(winesync) \
OVERLAY_PARAM_BOOL(present_mode) \
OVERLAY_PARAM_BOOL(time_no_label) \
OVERLAY_PARAM_CUSTOM(fps_sampling_period) \
OVERLAY_PARAM_CUSTOM(output_folder) \
OVERLAY_PARAM_CUSTOM(output_file) \
@ -142,7 +133,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(toggle_preset) \
OVERLAY_PARAM_CUSTOM(toggle_fps_limit) \
OVERLAY_PARAM_CUSTOM(toggle_logging) \
OVERLAY_PARAM_CUSTOM(reset_fps_metrics) \
OVERLAY_PARAM_CUSTOM(reload_cfg) \
OVERLAY_PARAM_CUSTOM(upload_log) \
OVERLAY_PARAM_CUSTOM(upload_logs) \
@ -163,7 +153,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(text_color) \
OVERLAY_PARAM_CUSTOM(wine_color) \
OVERLAY_PARAM_CUSTOM(battery_color) \
OVERLAY_PARAM_CUSTOM(network_color) \
OVERLAY_PARAM_CUSTOM(alpha) \
OVERLAY_PARAM_CUSTOM(log_duration) \
OVERLAY_PARAM_CUSTOM(pci_dev) \
@ -195,9 +184,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(text_outline_color) \
OVERLAY_PARAM_CUSTOM(text_outline_thickness) \
OVERLAY_PARAM_CUSTOM(fps_text) \
OVERLAY_PARAM_CUSTOM(device_battery) \
OVERLAY_PARAM_CUSTOM(fps_metrics) \
OVERLAY_PARAM_CUSTOM(network) \
enum overlay_param_position {
LAYER_POSITION_TOP_LEFT,
@ -270,9 +256,7 @@ struct overlay_params {
enum gl_size_query gl_size_query {GL_SIZE_DRAWABLE};
bool gl_dont_flip {false};
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;
unsigned cpu_color, gpu_color, vram_color, ram_color, engine_color, io_color, frametime_color, background_color, text_color, wine_color, battery_color;
std::vector<unsigned> gpu_load_color;
std::vector<unsigned> cpu_load_color;
std::vector<unsigned> gpu_load_value;
@ -295,7 +279,6 @@ struct overlay_params {
std::vector<KeySym> upload_log;
std::vector<KeySym> upload_logs;
std::vector<KeySym> toggle_hud_position;
std::vector<KeySym> reset_fps_metrics;
std::string time_format, output_folder, output_file;
std::string pci_dev;
std::string media_player_name;
@ -320,23 +303,18 @@ struct overlay_params {
size_t font_params_hash;
unsigned text_outline_color;
float text_outline_thickness;
std::vector<std::string> device_battery;
std::vector<std::string> fps_metrics;
std::vector<std::string> network;
};
const extern char *overlay_param_names[];
void parse_overlay_config(struct overlay_params *params,
const char *env, bool ignore_preset);
void presets(int preset, struct overlay_params *params, bool inherit=false);
void presets(int preset, struct overlay_params *params);
bool parse_preset_config(int preset, struct overlay_params *params);
void add_to_options(struct overlay_params *params, std::string option, std::string value);
#ifdef __cplusplus
}
#endif
extern std::mutex config_mtx;
extern std::condition_variable config_cv;
extern bool config_ready;
#endif /* MANGOHUD_OVERLAY_PARAMS_H */

@ -26,7 +26,6 @@ static void get_real_functions()
#endif
"*libc.so*",
"*libc.*.so*",
"*ld-musl-*.so*",
};
for (size_t i = 0; i < sizeof(libs) / sizeof(*libs); i++)

@ -35,11 +35,8 @@ bool init_x11() {
}
failed = !display;
if (failed && displayid)
if (failed)
SPDLOG_ERROR("XOpenDisplay failed to open display '{}'", displayid);
if (!displayid)
SPDLOG_DEBUG("DISPLAY env is not set");
return !!display;
}

@ -1,92 +0,0 @@
#include "shell.h"
#include <thread>
#include <iostream>
#include <sys/wait.h>
#include <spdlog/spdlog.h>
#include "string_utils.h"
#include <array>
std::string Shell::readOutput() {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::array<char, 128> buffer;
std::string result;
ssize_t count;
while ((count = ::read(from_shell[0], buffer.data(), buffer.size())) > 0) {
result.append(buffer.data(), count);
}
// Split the result into lines and return the last line
std::istringstream stream(result);
std::string line;
std::string last_line;
while (std::getline(stream, line)) {
last_line = line;
}
SPDLOG_DEBUG("Shell: recieved output: {}", last_line);
return last_line;
}
Shell::Shell() {
static bool failed;
if (pipe(to_shell) == -1) {
SPDLOG_ERROR("Failed to create to_shell pipe: {}", strerror(errno));
failed = true;
}
if (pipe(from_shell) == -1) {
SPDLOG_ERROR("Failed to create from_shell pipe: {}", strerror(errno));
failed = true;
}
// if either pipe fails, there's no point in continuing.
if (failed){
SPDLOG_ERROR("Shell has failed, will not be able to use exec");
return;
}
shell_pid = fork();
if (shell_pid == 0) { // Child process
close(to_shell[1]);
close(from_shell[0]);
dup2(to_shell[0], STDIN_FILENO);
dup2(from_shell[1], STDOUT_FILENO);
dup2(from_shell[1], STDERR_FILENO);
execl("/bin/sh", "sh", nullptr);
exit(1); // Exit if execl fails
} else {
close(to_shell[0]);
close(from_shell[1]);
// Set the read end of the from_shell pipe to non-blocking
setNonBlocking(from_shell[0]);
}
success = true;
}
std::string Shell::exec(std::string cmd) {
if (!success)
return "";
writeCommand(cmd);
return readOutput();
}
void Shell::writeCommand(std::string command) {
if (write(to_shell[1], command.c_str(), command.length()) == -1)
SPDLOG_ERROR("Failed to write to shell");
trim(command);
SPDLOG_DEBUG("Shell: wrote command: {}", command);
}
Shell::~Shell() {
if (write(to_shell[1], "exit\n", 5) == -1)
SPDLOG_ERROR("Failed exit shell");
close(to_shell[1]);
close(from_shell[0]);
waitpid(shell_pid, nullptr, 0);
}

@ -1,35 +0,0 @@
#pragma once
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#ifdef __linux__
#include <sys/wait.h>
#endif
#include <string>
#include <memory>
class Shell {
private:
int to_shell[2];
int from_shell[2];
pid_t shell_pid;
bool success;
#ifdef __linux__
void setNonBlocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
#endif
void writeCommand(std::string command);
std::string readOutput();
public:
Shell();
~Shell();
std::string exec(std::string cmd);
};
extern std::unique_ptr<Shell> shell;

@ -10,7 +10,6 @@
#include <algorithm>
#include <cctype>
#include <locale>
#include <cstring>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
@ -128,22 +127,6 @@ static std::vector<std::string> str_tokenize(const std::string& s, const std::st
return v;
}
static void trim_char(char* str) {
if(!str)
return;
char* ptr = str;
int len = strlen(ptr);
while(len-1 > 0 && isspace(ptr[len-1]))
ptr[--len] = 0;
while(*ptr && isspace(*ptr))
++ptr, --len;
memmove(str, ptr, len + 1);
}
#pragma GCC diagnostic pop
#endif //MANGOHUD_STRING_UTILS_H

@ -50,15 +50,6 @@
#include "notify.h"
#include "blacklist.h"
#include "pci_ids.h"
#if defined(HAVE_WAYLAND)
#include "wayland_hook.h"
#endif
#include "real_dlsym.h"
#include "file_utils.h"
#ifdef __linux__
#include <dlfcn.h>
#include "implot.h"
#endif
using namespace std;
@ -1319,9 +1310,6 @@ static void setup_swapchain_data(struct swapchain_data *data,
data->format = pCreateInfo->imageFormat;
data->imgui_context = ImGui::CreateContext(data->font_atlas);
#ifdef __linux__
ImPlot::CreateContext();
#endif
ImGui::SetCurrentContext(data->imgui_context);
ImGui::GetIO().IniFilename = NULL;
@ -1478,7 +1466,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data)
device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL);
shutdown_swapchain_font(data);
IM_DELETE(data->font_atlas);
IM_FREE(data->font_atlas);
ImGui::DestroyContext(data->imgui_context);
}
@ -1502,14 +1490,6 @@ static struct overlay_draw *before_present(struct swapchain_data *swapchain_data
return draw;
}
static bool IsPresentModeSupported(VkPresentModeKHR targetPresentMode, const std::vector<VkPresentModeKHR>& supportedPresentModes) {
for (const auto& mode : supportedPresentModes)
if (mode == targetPresentMode)
return true;
return false; // Not found
}
static VkResult overlay_CreateSwapchainKHR(
VkDevice device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
@ -1521,35 +1501,12 @@ static VkResult overlay_CreateSwapchainKHR(
createInfo.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
struct device_data *device_data = FIND(struct device_data, device);
auto params = device_data->instance->params;
if (device_data->instance->params.vsync < 4) {
HUDElements.cur_present_mode = HUDElements.presentModes[params.vsync];
createInfo.presentMode = HUDElements.cur_present_mode;
} else {
HUDElements.cur_present_mode = createInfo.presentMode;
}
struct instance_data *instance_data =
FIND(struct instance_data, device_data->physical_device);
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR =
(PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) instance_data->vtable.GetInstanceProcAddr(instance_data->instance, "vkGetPhysicalDeviceSurfacePresentModesKHR");
if (fpGetPhysicalDeviceSurfacePresentModesKHR != NULL) {
uint32_t presentModeCount;
std::vector<VkPresentModeKHR> presentModes(6);
VkResult result = fpGetPhysicalDeviceSurfacePresentModesKHR(device_data->physical_device, pCreateInfo->surface, &presentModeCount, presentModes.data());
if (result == VK_SUCCESS) {
if (IsPresentModeSupported(HUDElements.cur_present_mode, presentModes))
SPDLOG_DEBUG("Present mode: {}", HUDElements.presentModeMap[HUDElements.cur_present_mode]);
else {
SPDLOG_DEBUG("Present mode is not supported: {}", HUDElements.presentModeMap[HUDElements.cur_present_mode]);
HUDElements.cur_present_mode = VK_PRESENT_MODE_FIFO_KHR;
}
}
}
array<VkPresentModeKHR, 4> modes = {VK_PRESENT_MODE_FIFO_RELAXED_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_MAILBOX_KHR,
VK_PRESENT_MODE_FIFO_KHR};
if (device_data->instance->params.vsync < 4)
createInfo.presentMode = modes[device_data->instance->params.vsync];
VkResult result = device_data->vtable.CreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain);
if (result != VK_SUCCESS) return result;
@ -1564,7 +1521,6 @@ static VkResult overlay_CreateSwapchainKHR(
swapchain_data->sw_stats.engineVersion = device_data->instance->engineVersion;
swapchain_data->sw_stats.engine = device_data->instance->engine;
HUDElements.vendorID = prop.vendorID;
std::stringstream ss;
// ss << prop.deviceName;
if (prop.vendorID == 0x10de) {
@ -1588,7 +1544,7 @@ static VkResult overlay_CreateSwapchainKHR(
std::string deviceName = prop.deviceName;
if (!is_blacklisted()) {
#ifdef __linux__
swapchain_data->sw_stats.gpuName = remove_parentheses(deviceName);
swapchain_data->sw_stats.gpuName = deviceName;
#endif
}
swapchain_data->sw_stats.driverName = driverProps.driverInfo;
@ -1805,7 +1761,6 @@ static VkResult overlay_CreateDevice(
pCreateInfo->enabledExtensionCount);
uint32_t extension_count;
instance_data->vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, nullptr);
std::vector<VkExtensionProperties> available_extensions(extension_count);
@ -2033,23 +1988,6 @@ static void overlay_DestroyInstance(
destroy_instance_data(instance_data);
}
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
static VkResult overlay_CreateWaylandSurfaceKHR(
VkInstance instance,
const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface
)
{
struct instance_data *instance_data = FIND(struct instance_data, instance);
if (!wl_handle)
wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
wl_display_ptr = pCreateInfo->display;
init_wayland_data();
return instance_data->vtable.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
}
#endif
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev,
const char *funcName);
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance,
@ -2070,9 +2008,6 @@ static const struct {
ADD_HOOK(EndCommandBuffer),
ADD_HOOK(CmdExecuteCommands),
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
ADD_HOOK(CreateWaylandSurfaceKHR),
#endif
ADD_HOOK(CreateSwapchainKHR),
ADD_HOOK(QueuePresentKHR),
ADD_HOOK(DestroySwapchainKHR),

@ -1,63 +0,0 @@
#include <cstdint>
#include <array>
#include <dlfcn.h>
#include <cstdio>
#include "real_dlsym.h"
#include "wayland_hook.h"
EXPORT_C_(struct wl_display*) wl_display_connect(const char *name);
EXPORT_C_(struct wl_display*) wl_display_connect_to_fd(int fd);
typedef struct wl_display* (*pwl_display_connect)(const char *name);
typedef struct wl_display* (*pwl_display_connect_to_fd)(int fd);
pwl_display_connect wl_display_connect_ptr = nullptr;
pwl_display_connect_to_fd wl_display_connect_to_fd_ptr = nullptr;
void* wl_handle = nullptr;
struct wl_display* wl_display_ptr = nullptr;
EXPORT_C_(struct wl_display*) wl_display_connect(const char *name)
{
struct wl_display *ret = nullptr;
if (!wl_handle) {
wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
}
if (wl_handle) {
wl_display_connect_ptr = (pwl_display_connect)real_dlsym(wl_handle, "wl_display_connect");
wl_display_connect_to_fd_ptr = (pwl_display_connect_to_fd)real_dlsym(wl_handle, "wl_display_connect_to_fd");
ret = wl_display_connect_ptr(name);
if (!wl_display_ptr) {
wl_display_ptr = ret;
init_wayland_data();
}
}
return ret;
}
EXPORT_C_(struct wl_display*) wl_display_connect_to_fd(int fd)
{
struct wl_display *ret = nullptr;
if (!wl_handle) {
wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
}
if (wl_handle) {
wl_display_connect_to_fd_ptr = (pwl_display_connect_to_fd)real_dlsym(wl_handle, "wl_display_connect_to_fd");
wl_display_connect_ptr = (pwl_display_connect)real_dlsym(wl_handle, "wl_display_connect");
ret = wl_display_connect_to_fd_ptr(fd);
if (!wl_display_ptr) {
wl_display_ptr = ret;
init_wayland_data();
}
}
return ret;
}

@ -1,13 +0,0 @@
#include <wayland-client.h>
#include <vector>
#ifndef KeySym
typedef unsigned long KeySym;
#endif
extern void* wl_handle;
extern struct wl_display* wl_display_ptr;
extern std::vector<KeySym> wl_pressed_keys;
void init_wayland_data();
void update_wl_queue();

@ -1,118 +0,0 @@
#include <cstdint>
#include <cstring>
#include <array>
#include <algorithm>
#include <unistd.h>
#include <vector>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <sys/mman.h>
#include "wayland_hook.h"
#include "timing.hpp"
#include "keybinds.h"
struct wl_seat* seat = nullptr;
struct wl_keyboard* keyboard = nullptr;
struct xkb_context *context_xkb = nullptr;
struct xkb_keymap *keymap_xkb = nullptr;
struct xkb_state *state_xkb = nullptr;
struct wl_event_queue* queue = nullptr;
std::vector<KeySym> wl_pressed_keys {};
static void registry_handle_global(void *data, struct wl_registry* registry, uint32_t name, const char *interface, uint32_t version)
{
if(strcmp(interface, wl_seat_interface.name) == 0)
{
seat = (struct wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 7);
}
}
static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name){}
static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
{
char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if(!context_xkb)
context_xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if(keymap_xkb && state_xkb)
{
xkb_keymap_unref(keymap_xkb);
xkb_state_unref(state_xkb);
}
keymap_xkb = xkb_keymap_new_from_string(
context_xkb, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS);
state_xkb = xkb_state_new(keymap_xkb);
munmap((void*)map_shm, size);
close(fd);
}
static void wl_keyboard_enter(void *user_data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys){}
static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
{
wl_pressed_keys.clear();
}
static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
xkb_keycode_t keycode = key + 8;
xkb_keysym_t keysym = xkb_state_key_get_one_sym(state_xkb, keycode);
if(state)
{
wl_pressed_keys.push_back(keysym);
}
else
{
auto it = std::find(wl_pressed_keys.begin(), wl_pressed_keys.end(), keysym);
if(it != wl_pressed_keys.end())
wl_pressed_keys.erase(it);
}
}
static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group){}
static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){}
struct wl_registry_listener registry_listener {
.global = registry_handle_global,
.global_remove = registry_handle_global_remove
};
struct wl_keyboard_listener keyboard_listener {
.keymap = wl_keyboard_keymap,
.enter = wl_keyboard_enter,
.leave = wl_keyboard_leave,
.key = wl_keyboard_key,
.modifiers = wl_keyboard_modifiers,
.repeat_info = wl_keyboard_repeat_info
};
void update_wl_queue()
{
wl_display_roundtrip_queue(wl_display_ptr, queue);
}
void init_wayland_data()
{
if (!wl_display_ptr)
return;
struct wl_display *display_wrapped = (struct wl_display*)wl_proxy_create_wrapper(wl_display_ptr);
queue = wl_display_create_queue(wl_display_ptr);
wl_proxy_set_queue((struct wl_proxy*)display_wrapped, queue);
wl_registry *registry = wl_display_get_registry(display_wrapped);
wl_proxy_wrapper_destroy(display_wrapped);
wl_registry_add_listener(registry, &registry_listener, NULL);
update_wl_queue();
update_wl_queue();
keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
update_wl_queue();
}

@ -1,82 +0,0 @@
#include "file_utils.h"
#include <filesystem.h>
#include <string>
namespace fs = ghc::filesystem;
class WineSync {
private:
enum syncMethods {
NONE,
WINESERVER,
ESYNC,
FSYNC,
NTSYNC
};
int method = 0;
bool inside_wine = true;
const char* methods[5] = {
"NONE",
"Wserver",
"Esync",
"Fsync",
"NTsync"
};
public:
WineSync() {
#ifdef __linux__
// check that's were inside wine
std::string wineProcess = get_exe_path();
auto n = wineProcess.find_last_of('/');
std::string preloader = wineProcess.substr(n + 1);
if (preloader != "wine-preloader" && preloader != "wine64-preloader"){
inside_wine = false;
return;
}
const char* paths[2] {
"/proc/self/map_files",
"/proc/self/fd"
};
// check which sync wine is using, if any.
fs::path path;
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
path = paths[i];
for (auto& p : fs::directory_iterator(path)) {
auto filepath = p.path().string();
const char* filename = filepath.c_str();
auto sym = read_symlink(filename);
if (sym.find("winesync") != std::string::npos)
method = syncMethods::NTSYNC;
else if (sym.find("fsync") != std::string::npos)
method = syncMethods::FSYNC;
else if (sym.find("ntsync") != std::string::npos)
method = syncMethods::NTSYNC;
else if (sym.find("esync") != std::string::npos)
method = syncMethods::ESYNC;
if (method)
break;
}
if (method)
break;
}
#endif
};
bool valid() {
return inside_wine;
}
// return sync method as display name
std::string get_method() {
return methods[method];
}
};
extern std::unique_ptr<WineSync> winesync_ptr;

@ -1,13 +1,11 @@
[wrap-file]
directory = imgui-1.89.9
source_url = https://github.com/ocornut/imgui/archive/refs/tags/v1.89.9.tar.gz
source_filename = imgui-1.89.9.tar.gz
source_hash = 1acc27a778b71d859878121a3f7b287cd81c29d720893d2b2bf74455bf9d52d6
patch_filename = imgui_1.89.9-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/imgui_1.89.9-1/get_patch
patch_hash = 9b21290c597d76bf8d4eeb3f9ffa024b11d9ea6c61e91d648ccc90b42843d584
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/imgui_1.89.9-1/imgui-1.89.9.tar.gz
wrapdb_version = 1.89.9-1
directory = imgui-1.81
source_url = https://github.com/ocornut/imgui/archive/v1.81.tar.gz
source_filename = imgui-1.81.tar.gz
source_hash = f7c619e03a06c0f25e8f47262dbc32d61fd033d2c91796812bf0f8c94fca78fb
patch_url = https://wrapdb.mesonbuild.com/v2/imgui_1.81-1/get_patch
patch_filename = imgui-1.81-1-wrap.zip
patch_hash = 6d00b442690b6a5c5d8f898311daafbce16d370cf64f53294c3b8c5c661e435f
[provide]
imgui = imgui_dep

@ -1,13 +0,0 @@
[wrap-file]
directory = implot-0.16
source_url = https://github.com/epezent/implot/archive/refs/tags/v0.16.zip
source_filename = implot-0.16.zip
source_hash = 24f772c688f6b8a6e19d7efc10e4923a04a915f13d487b08b83553aa62ae1708
patch_filename = implot_0.16-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/implot_0.16-1/get_patch
patch_hash = 1c6b1462066a5452fa50c1da1dd47fed841f28232972c82d778f2962936568c7
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/implot_0.16-1/implot-0.16.zip
wrapdb_version = 0.16-1
[provide]
implot = implot_dep

@ -1,13 +1,12 @@
[wrap-file]
directory = spdlog-1.14.1
source_url = https://github.com/gabime/spdlog/archive/refs/tags/v1.14.1.tar.gz
source_filename = spdlog-1.14.1.tar.gz
source_hash = 1586508029a7d0670dfcb2d97575dcdc242d3868a259742b69f100801ab4e16b
patch_filename = spdlog_1.14.1-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.14.1-1/get_patch
patch_hash = ae878e732330ea1048f90d7e117c40c0cd2a6fb8ae5492c7955818ce3aaade6c
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/spdlog_1.14.1-1/spdlog-1.14.1.tar.gz
wrapdb_version = 1.14.1-1
directory = spdlog-1.8.5
source_url = https://github.com/gabime/spdlog/archive/v1.8.5.tar.gz
source_filename = v1.8.5.tar.gz
source_hash = 944d0bd7c763ac721398dca2bb0f3b5ed16f67cef36810ede5061f35a543b4b8
patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.8.5-1/get_patch
patch_filename = spdlog-1.8.5-1-wrap.zip
patch_hash = 3c38f275d5792b1286391102594329e98b17737924b344f98312ab09929b74be
[provide]
spdlog = spdlog_dep

@ -85,7 +85,7 @@ static void test_amdgpu_get_samples_and_copy(void **state) {
static void test_amdgpu_get_metrics(void **state) {
UNUSED(state);
amdgpu_get_metrics(0x1435);
amdgpu_get_metrics();
}
const struct CMUnitTest amdgpu_tests[] = {

Loading…
Cancel
Save