Merge branch 'develop'

pull/431/head^2
jackun 3 years ago
commit b3a95f1bca
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

1
.gitignore vendored

@ -40,6 +40,7 @@ lib32-mangohud*.tar.*
subprojects/packagecache/
subprojects/Vulkan-Headers-*/
subprojects/imgui-*/
subprojects/spdlog-*/
#GNU Global Metadata
**/GPATH

@ -16,20 +16,67 @@ git clone --recurse-submodules https://github.com/flightlessmango/MangoHud.git
cd MangoHud
```
To build it, execute:
Using `meson` to install "manually":
```
./build.sh build
./build.sh package
meson build
ninja -C build install
```
**NOTE: If you are running an Ubuntu-based, Arch-based, Fedora-based, or openSUSE-based distro, the build script will automatically detect and prompt you to install missing build dependencies. If you run into any issues with this please report them!**
By default, meson should install MangoHud to `/usr/local`. Specify install prefix with `--prefix=/usr` if desired.
Add `-Dappend_libdir_mangohud=false` option to meson to not append `mangohud` to libdir if desired (e.g. /usr/local/lib/mangohud).
To install 32-bit build on 64-bit distro, specify proper `libdir`: `lib32` for Arch, `lib/i386-linux-gnu` on Debian. RPM-based distros usually install 32-bit libraries to `/usr/lib` and 64-bit to `/usr/lib64`.
You may have to change `PKG_CONFIG_PATH` to point to correct folders for your distro.
```
CC="gcc -m32" \
CXX="g++ -m32" \
PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig" \
meson build32 --libdir lib32
ninja -C build32 install
```
### Dependencies
Install necessary development packages.
- gcc, g++
- or gcc-multilib, g++-multilib for 32-bit support
- meson >=0.54
- ninja (ninja-build)
- glslang
- vulkan headers if using `-Duse_system_vulkan=enabled` option with `meson`
- libGL/libEGL (libglvnd, mesa-common-dev, mesa-libGL-devel etc)
- X11 (libx11-dev)
- libdrm (libdrm-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
Python 3 libraries:
- Mako (python3-mako or install with `pip`)
If distro's packaged `meson` is too old and gives build errors, install newer version with `pip` (`python3-pip`).
### Building with build script
You can also use `build.sh` script to do some things automatically like install dependencies, if distro is supported but it usually assumes you are running on x86_64 architecture.
To just build it, execute:
```
./build.sh build
```
Once done, proceed to the [installation](#source).
You can also pass arguments to meson:
## Install
```
./build.sh build -Dwith_xnvctrl=disabled
```
### Source
Resulting files will be install to `./build/release` folder.
If you have compiled MangoHud from source, to install it, execute:
@ -43,6 +90,29 @@ You can then subsequently uninstall MangoHud via the following command
./build.sh uninstall
```
To tar up the resulting binaries into a package and create a release tar with installer script, execute:
```
./build.sh package release
```
or combine the commands, although `package` should also call `build` if it doesn't find the built libs:
```
./build.sh build package release
```
If you have built MangoHud before and suddenly it fails, you can try cleaning the `build` folder, execute:
```
./build.sh clean
```
Currently it just does `rm -fr build` and clears subprojects.
**NOTE: If you are running an Ubuntu-based, Arch-based, Fedora-based, or openSUSE-based distro, the build script will automatically detect and prompt you to install missing build dependencies. If you run into any issues with this please report them!**
### Pre-packaged binaries
#### GitHub releases
@ -172,7 +242,9 @@ Some Linux native OpenGL games overrides LD_PRELOAD and stops MangoHud from work
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:
1. `/path/to/application/dir/MangoHud.conf`
2. `$HOME/.config/MangoHud/{application_name}.conf`
2. Per-application configuration in ~/.config/MangoHud:
1. `$HOME/.config/MangoHud/application_name.conf`
2. `$HOME/.config/MangoHud/wine-application_name.conf` for wine/proton apps
3. `$HOME/.config/MangoHud/MangoHud.conf`
You can find an example config in /usr/share/doc/mangohud
@ -197,6 +269,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `gpu_core_clock`<br>`gpu_mem_clock`| Displays GPU core/memory frequency |
| `ram`<br>`vram` | Displays system RAM/VRAM usage |
| `swap` | Displays swap space usage next to system RAM usage |
| `procmem`<br>`procmem_shared`, `procmem_virt`| Displays process' memory usage: resident, shared and/or virtual. `procmem` (resident) also toggles others off if disabled. |
| `full` | Enables most of the toggleable parameters (currently excludes `histogram`) |
| `font_size=` | Customizeable font size (default=24) |
| `font_size_text=` | Customizeable font size for other text like media metadata (default=24) |
@ -221,7 +294,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `vsync`<br> `gl_vsync` | Set vsync for OpenGL or Vulkan |
| `media_player` | Show media player metadata |
| `media_player_name` | Force media player DBus service name without the `org.mpris.MediaPlayer2` part, like `spotify`, `vlc`, `audacious` or `cantata`. If none is set, MangoHud tries to switch between currently playing players. |
| `media_player_order` | Media player metadata field order. Defaults to `title,artist,album`. |
| `media_player_format` | Format media player metadata. Add extra text etc. Semi-colon breaks to new line. Defaults to `{title};{artist};{album}`. |
| `font_scale_media_player` | Change size of media player text relative to font_size |
| `io_read`<br> `io_write` | Show non-cached IO read/write, in MiB/s |
| `pci_dev` | Select GPU device in multi-gpu setups |
@ -263,6 +336,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `battery` | Display current battery percent and energy consumption |
| `battery_icon` | Display battery icon instead of percent |
| `battery_color` | Change the BATT text color |
| `force_amdgpu_hwmon` | Use hwmon sysfs instead of libdrm for amdgpu stats |
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.

@ -5,7 +5,7 @@
################ PERFORMANCE #################
### Limit the application FPS. Comma-separated list of one or more FPS values (e.g. 0,30,60). 0 means unlimited (unless VSynced).
### Limit the application FPS. Comma-separated list of one or more FPS values (e.g. 0,30,60). 0 means unlimited (unless VSynced)
# fps_limit=
### VSync [0-3] 0 = adaptive; 1 = off; 2 = mailbox; 3 = on
@ -16,104 +16,135 @@
################### VISUAL ###################
### Custom text centered useful for a header
# custom_text_center =
### Legacy layout
# legacy_layout = false
# legacy_layout=false
### Display the current CPU information
cpu_stats
# cpu_temp
# cpu_power
# cpu_text = "CPU"
# cpu_mhz
# cpu_load_change
# cpu_load_value
# cpu_load_color
### Display custom centered text, useful for a header
# custom_text_center=
### Display the current system time
# time
### Time formatting examples
# time_format=%H:%M
# time_format=[ %T %F ]
# time_format=%X # locally formatted time, because of limited glyph range, missing characters may show as '?' (e.g. Japanese)
### Display MangoHud version
# version
### Display the current GPU information
gpu_stats
# gpu_temp
# gpu_core_clock
# gpu_mem_clock
# gpu_name
# gpu_power
# gpu_text = "GPU"
# vulkan_driver
# gpu_text=GPU
# gpu_load_change
# gpu_load_value
# gpu_load_color
# gpu_load_value=60,90
# gpu_load_color=39F900,FDFD09,B22222
### Display the current CPU information
cpu_stats
# cpu_temp
# cpu_power
# cpu_text=CPU
# cpu_mhz
# cpu_load_change
# cpu_load_value=60,90
# cpu_load_color=39F900,FDFD09,B22222
### Display the current CPU load & frequency for each core
# core_load
# core_load_change
### Display IO read and write for the app (not system)
# io_stats
# io_read
# io_write
### Display system vram / ram / swap space usage
# vram
# ram
# swap
### Display per process memory usage
## Show resident memory and other types, if enabled
# procmem
# procmem_shared
# procmem_virt
### Display battery information
# battery
# battery_icon
### Display FPS and frametime
fps
# fps_sampling_period=
# fps_sampling_period=500
# fps_color_change
# fps_value=30,60
# fps_color=B22222,FDFD09,39F900
frametime
### Display miscellaneus information
# engine_version
# gpu_name
# vulkan_driver
# wine
### Display loaded MangoHud architecture
# arch
### Display the frametime line graph
frame_timing
#histogram
# histogram
### Display the current system time
# time
### Display GameMode / vkBasalt running status
# gamemode
# vkbasalt
### Display current FPS limit
# show_fps_limit
### Display the current resolution
# resolution
### Show current fps limit
# show_fps_limit
### Display custom text
# custom_text
# custom_text=
### Display output of Bash command in next column
# exec=
### Time formatting examples
# time_format = %H:%M
# time_format = [ %T %F ]
# time_format = %X # locally formatted time, because of limited glyph range, missing characters may show as '?' (e.g. Japanese)
### Display media player metadata
# media_player
# media_player_name=spotify
## Format metadata, lines are delimited by ; (wip)
# media_player_format={title};{artist};{album}
# media_player_format=Track:;{title};By:;{artist};From:;{album}
### Change the hud font size (default is 24)
font_size=24
### Change the hud font size
# font_size=24
# font_scale=1.0
# font_size_text=24
# font_scale_media_player = 0.55
# font_scale_media_player=0.55
# no_small_font
### Change default font (set location to .TTF/.OTF file )
### Change default font (set location to TTF/OTF file)
## Set font for the whole hud
# font_file=
## Set font only for text like media player metadata
# font_file_text=
## Set font glyph ranges. Defaults to latin-only. Don't forget to set font_file/text_font_file to font that supports these.
## Probably don't enable all at once because of memory usage and hardware limits concerns.
## If you experience crashes or text is just squares, reduce glyph range or reduce font size.
# font_glyph_ranges=korean, chinese, chinese_simplified, japanese, cyrillic, thai, vietnamese, latin_ext_a, latin_ext_b
### Change the hud position (default is top-left)
position=top-left
## Set font glyph ranges. Defaults to Latin-only. Don't forget to set font_file/font_file_text to font that supports these
## Probably don't enable all at once because of memory usage and hardware limits concerns
## If you experience crashes or text is just squares, reduce glyph range or reduce font size
# font_glyph_ranges=korean,chinese,chinese_simplified,japanese,cyrillic,thai,vietnamese,latin_ext_a,latin_ext_b
### Display the current CPU load & frequency for each core
# core_load
# core_load_change
### IO read and write for the app (not system)
# io_read
# io_write
# io_stats
### Display system ram / swap space / vram usage
# ram
# swap
# vram
### Change the hud position
# position=top-left
### Display MangoHud, engine or Wine version
# version
# engine_version
# wine
### Change the corner roundness
# round_corners=
### Disable / hide the hud by default
# no_display
@ -129,7 +160,7 @@ position=top-left
# cellpadding_y=
### Hud transparency / alpha
background_alpha=0.5
# background_alpha=0.5
# alpha=
### Color customization
@ -143,32 +174,28 @@ background_alpha=0.5
# frametime_color=00FF00
# background_color=020202
# media_player_color=FFFFFF
# wine_color=732010
### Show media player metadata
# media_player
# media_player_name = spotify
# media_player_order = title,artist,album
# wine_color=EB5B5B
# battery_color=FF9078
### Specify gpu with pci bus id for amdgpu and NVML stats.
### Specify GPU with PCI bus ID for AMDGPU and NVML stats
### Set to 'domain:bus:slot.function'
# pci_dev = 0:0a:0.0
# pci_dev=0:0a:0.0
### Blacklist
# blacklist =
# blacklist=
################## WORKAROUNDS #################
### Options starting with "gl_*" are for OpenGL.
### Specify what to use for getting display size. Options are "viewport", "scissorbox" or disabled. Defaults to using glXQueryDrawable.
# gl_size_query = viewport
################ WORKAROUNDS #################
### Options starting with "gl_*" are for OpenGL
### Specify what to use for getting display size. Options are "viewport", "scissorbox" or disabled. Defaults to using glXQueryDrawable
# gl_size_query=viewport
### (Re)bind given framebuffer before MangoHud gets drawn. Helps with Crusader Kings III.
# gl_bind_framebuffer = 0
### (Re)bind given framebuffer before MangoHud gets drawn. Helps with Crusader Kings III
# gl_bind_framebuffer=0
### Don't swap origin if using GL_UPPER_LEFT. Helps with Ryujinx.
# gl_dont_flip = 1
### Don't swap origin if using GL_UPPER_LEFT. Helps with Ryujinx
# gl_dont_flip=1
################## INTERACTION #################
################ INTERACTION #################
### Change toggle keybinds for the hud & logging
# toggle_hud=Shift_R+F12
@ -177,15 +204,17 @@ background_alpha=0.5
# reload_cfg=Shift_L+F4
# upload_log=Shift_L+F3
################## LOG #################
#################### LOG #####################
### Automatically start the log after X seconds
# autostart_log = 1
# autostart_log=1
### Set amount of time in seconds that the logging will run for
# log_duration
# log_duration=
### Change the default log interval, 100 is default
# log_interval=100
### Set location of the output files (required for logging)
# output_folder = /home/<USERNAME>/mangologs
# output_folder=/home/<USERNAME>/mangologs
### Permit uploading logs directly to FlightlessMango.com
# permit_upload=1
### Define a '+'-separated list of percentiles shown in the benchmark results.
### Define a '+'-separated list of percentiles shown in the benchmark results
### Use "AVG" to get a mean average. Default percentiles are 97+AVG+1+0.1
# benchmark_percentiles=
# benchmark_percentiles=97,AVG,1,0.1

@ -1,12 +1,19 @@
#!/usr/bin/env bash
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
MANGOHUD_CONFIG_DIR="$XDG_CONFIG_HOME/MangoHud"
SU_CMD=$(command -v sudo || command -v doas)
SU_CMD=$(command -v sudo || command -v doas || echo)
# doas requires a double dash if the command it runs will include any dashes,
# so append a double dash to the command
[[ $SU_CMD == *doas ]] && SU_CMD="$SU_CMD -- "
# Correctly identify the os-release file.
for os_release in ${OS_RELEASE_FILES[@]} ; do
if [[ ! -e "${os_release}" ]]; then
continue
fi
DISTRO=$(sed -rn 's/^ID(_LIKE)*=(.+)/\2/p' ${os_release} | sed 's/"//g')
done
mangohud_usage() {
echo 'Accepted arguments: "install", "uninstall".'
@ -43,39 +50,56 @@ mangohud_install() {
mangohud_uninstall
install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so
install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_dlsym.so /usr/lib/mangohud/lib32/libMangoHud_dlsym.so
DEFAULTLIB=lib32
for i in $DISTRO; do
case $i in
*arch*)
DEFAULTLIB=lib64
;;
esac
done
echo DEFAULTLIB: $DEFAULTLIB
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud_dlsym.so /usr/lib/mangohud/lib64/libMangoHud_dlsym.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_dlsym.so /usr/lib/mangohud/lib32/libMangoHud_dlsym.so
/usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.json /usr/share/vulkan/implicit_layer.d/MangoHud.json
/usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.json /usr/share/vulkan/implicit_layer.d/MangoHud.json
/usr/bin/install -Dvm644 ./build/release/usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1
/usr/bin/install -Dvm644 ./build/release/usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example
/usr/bin/install -vm755 ./build/release/usr/bin/mangohud /usr/bin/mangohud
ln -sv $DEFAULTLIB /usr/lib/mangohud/lib
install -Dvm644 ./usr/lib/mangohud/lib/libMangoHud.so /usr/lib/mangohud/lib/libMangoHud.so
install -Dvm644 ./usr/lib/mangohud/lib/libMangoHud_dlsym.so /usr/lib/mangohud/lib/libMangoHud_dlsym.so
# FIXME get the triplet somehow
ln -sv lib64 /usr/lib/mangohud/x86_64
ln -sv lib64 /usr/lib/mangohud/x86_64-linux-gnu
ln -sv . /usr/lib/mangohud/lib64/x86_64
ln -sv . /usr/lib/mangohud/lib64/x86_64-linux-gnu
install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.json /usr/share/vulkan/implicit_layer.d/MangoHud.json
install -Dvm644 ./usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example
install -Dvm644 ./usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1
install -vm755 ./usr/bin/mangohud /usr/bin/mangohud
ln -sv lib32 /usr/lib/mangohud/i686
ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu
ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu
# FIXME get the triplet somehow
mkdir -p /usr/lib/mangohud/tls
ln -sv ../lib /usr/lib/mangohud/tls/x86_64
ln -sv ../lib64 /usr/lib/mangohud/tls/x86_64
ln -sv ../lib32 /usr/lib/mangohud/tls/i686
# Some distros search in $prefix/x86_64-linux-gnu/tls/x86_64 etc instead
ln -sv . /usr/lib/mangohud/lib/i686-linux-gnu
ln -sv . /usr/lib/mangohud/lib/x86_64-linux-gnu
if [ ! -e /usr/lib/mangohud/lib/i386-linux-gnu ]; then
ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu
fi
if [ ! -e /usr/lib/mangohud/lib/i686-linux-gnu ]; then
ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu
fi
if [ ! -e /usr/lib/mangohud/lib/x86_64-linux-gnu ]; then
ln -sv ../lib64 /usr/lib/mangohud/lib/x86_64-linux-gnu
fi
# $LIB can be "lib/tls/x86_64"?
ln -sv ../tls /usr/lib/mangohud/lib/tls
ln -sv lib /usr/lib/mangohud/lib64
ln -sv lib /usr/lib/mangohud/x86_64
ln -sv lib /usr/lib/mangohud/x86_64-linux-gnu
ln -sv . /usr/lib/mangohud/lib/x86_64
ln -sv lib32 /usr/lib/mangohud/i686
ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu
ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu
ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu
ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu
#ln -sv lib /usr/lib/mangohud/aarch64-linux-gnu
#ln -sv lib /usr/lib/mangohud/arm-linux-gnueabihf
rm -rf ./usr
echo "MangoHud Installed"

@ -28,7 +28,7 @@ dependencies() {
}
echo "# Checking Dependencies"
DEPS=(${LOCAL_CC}-multilib ${LOCAL_CXX}-multilib unzip)
DEPS=(${LOCAL_CC}-multilib ${LOCAL_CXX}-multilib unzip libdrm-dev)
install
@ -42,7 +42,7 @@ dependencies() {
set -e
if [[ ! -f ./bin/get-pip.py ]]; then
curl https://bootstrap.pypa.io/get-pip.py -o bin/get-pip.py
curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o bin/get-pip.py
python3 ./bin/get-pip.py
fi
pip3 install 'meson>=0.54' mako
@ -81,7 +81,7 @@ configure() {
build() {
if [[ ! -f "build-srt/meson64/build.ninja" || ! -f "build-srt/meson32/build.ninja" ]]; then
configure
configure $@
fi
DESTDIR="$PWD/build-srt/release" ninja -C build-srt/meson32 install
DESTDIR="$PWD/build-srt/release" ninja -C build-srt/meson64 install

@ -9,8 +9,8 @@ fi
SRCDIR=$PWD
BRANCH="${1:-master}"
# soldier 0.20201022.1 or newer
# scout 0.20201104.0 or newer
# soldier 0.20210618.0 or newer
# scout 0.20210630.0 or newer
RUNTIME="${2:-soldier}"
VERSION="${3:-0.20210618.0}"
IMAGE="steamrt_${RUNTIME}_${VERSION}_amd64:mango-${RUNTIME}"

@ -10,7 +10,8 @@ LAYER="build/release/usr/share/vulkan/implicit_layer.d/mangohud.json"
INSTALL_DIR="build/package/"
IMPLICIT_LAYER_DIR="$XDG_DATA_HOME/vulkan/implicit_layer.d"
VERSION=$(git describe --long --tags --always | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//')
SU_CMD=$(command -v sudo || command -v doas)
SU_CMD=$(command -v sudo || command -v doas || echo)
MACHINE=$(uname -m || echo)
# doas requires a double dash if the command it runs will include any dashes,
# so append a double dash to the command
@ -21,7 +22,7 @@ for os_release in ${OS_RELEASE_FILES[@]} ; do
if [[ ! -e "${os_release}" ]]; then
continue
fi
DISTRO=$(sed -rn 's/^NAME=(.+)/\1/p' ${os_release} | sed 's/"//g')
DISTRO=$(sed -rn 's/^ID(_LIKE)*=(.+)/\L\2/p' ${os_release} | sed 's/"//g')
done
dependencies() {
@ -50,16 +51,18 @@ dependencies() {
fi
set -e
}
echo "# Checking Dependencies"
case $DISTRO in
"Arch Linux"|"Manjaro Linux")
for i in $DISTRO; do
echo "# Checking dependencies for \"$i\""
case $i in
*arch*|*manjaro*)
MANAGER_QUERY="pacman -Q"
MANAGER_INSTALL="pacman -S"
DEPS="{gcc,meson,pkgconf,python-mako,glslang,libglvnd,lib32-libglvnd,libxnvctrl}"
DEPS="{gcc,meson,pkgconf,python-mako,glslang,libglvnd,lib32-libglvnd,libxnvctrl,libdrm}"
dep_install
break
;;
"Fedora")
*fedora*)
MANAGER_QUERY="dnf list installed"
MANAGER_INSTALL="dnf install"
DEPS="{meson,gcc,gcc-c++,libX11-devel,glslang,python3-mako,mesa-libGL-devel,libXNVCtrl-devel,dbus-devel}"
@ -68,8 +71,10 @@ dependencies() {
unset INSTALL
DEPS="{glibc-devel.i686,libstdc++-devel.i686,libX11-devel.i686}"
dep_install
break
;;
*"buntu"|"Linux Mint"|"Debian GNU/Linux"|"Zorin OS"|"Pop!_OS"|"elementary OS"|"KDE neon"|"Deepin")
*debian*|*ubuntu*|*deepin*)
MANAGER_QUERY="dpkg-query -s"
MANAGER_INSTALL="apt install"
DEPS="{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}"
@ -79,36 +84,31 @@ dependencies() {
$SU_CMD pip3 install 'meson>=0.54' mako
fi
if [[ ! -f /usr/local/bin/glslangValidator ]]; then
wget https://github.com/KhronosGroup/glslang/releases/download/SDK-candidate-26-Jul-2020/glslang-master-linux-Release.zip
wget https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip
unzip glslang-master-linux-Release.zip bin/glslangValidator
$SU_CMD install -m755 bin/glslangValidator /usr/local/bin/
$SU_CMD /usr/bin/install -m755 bin/glslangValidator /usr/local/bin/
rm bin/glslangValidator glslang-master-linux-Release.zip
fi
break
;;
"openSUSE Leap"|"openSUSE Tumbleweed")
*suse*)
PACKMAN_PKGS="libXNVCtrl-devel"
case $DISTRO in
"openSUSE Leap")
echo "You may have to enable packman repository for some extra packages: ${PACKMAN_PKGS}"
echo "zypper ar -cfp 90 https://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Leap_15.1/ packman"
;;
"openSUSE Tumbleweed")
echo "You may have to enable packman repository for some extra packages: ${PACKMAN_PKGS}"
echo "zypper ar -cfp 90 http://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/ packman"
;;
esac
echo "You may have to enable packman repository for some extra packages: ${PACKMAN_PKGS}"
echo "Leap: zypper ar -cfp 90 https://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Leap_15.1/ packman"
echo "Tumbleweed: zypper ar -cfp 90 http://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/ packman"
MANAGER_QUERY="rpm -q"
MANAGER_INSTALL="zypper install"
DEPS="{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,${PACKMAN_PKGS}}"
DEPS="{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,libdrm-devel,${PACKMAN_PKGS}}"
dep_install
if [[ $(pip3 show meson; echo $?) == 1 ]]; then
$SU_CMD pip3 install 'meson>=0.54'
fi
break
;;
"Solus")
*solus*)
unset MANAGER_QUERY
unset DEPS
MANAGER_INSTALL="eopkg it"
@ -130,11 +130,13 @@ dependencies() {
INSTALL="${INSTALL}""-c system.devel "
fi
dep_install
break
;;
*)
echo "# Unable to find distro information!"
echo "# Attempting to build regardless"
esac
done
fi
}
@ -142,9 +144,9 @@ configure() {
dependencies
git submodule update --init --depth 50
if [[ ! -f "build/meson64/build.ninja" ]]; then
meson build/meson64 --libdir lib/mangohud/lib --prefix /usr -Dappend_libdir_mangohud=false -Dld_libdir_prefix=true -Dld_libdir_abs=true $@ ${CONFIGURE_OPTS}
meson build/meson64 --libdir lib/mangohud/lib64 --prefix /usr -Dappend_libdir_mangohud=false -Dld_libdir_prefix=true -Dld_libdir_abs=true $@ ${CONFIGURE_OPTS}
fi
if [[ ! -f "build/meson32/build.ninja" ]]; then
if [[ ! -f "build/meson32/build.ninja" && "$MACHINE" = "x86_64" ]]; then
export CC="gcc -m32"
export CXX="g++ -m32"
export PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}"
@ -157,12 +159,15 @@ build() {
if [[ ! -f "build/meson64/build.ninja" ]]; then
configure $@
fi
DESTDIR="$PWD/build/release" ninja -C build/meson32 install
DESTDIR="$PWD/build/release" ninja -C build/meson64 install
if [ "$MACHINE" = "x86_64" ]; then
DESTDIR="$PWD/build/release" ninja -C build/meson32 install
fi
}
package() {
LIB="build/release/usr/lib/mangohud/lib/libMangoHud.so"
LIB="build/release/usr/lib/mangohud/lib64/libMangoHud.so"
LIB32="build/release/usr/lib/mangohud/lib32/libMangoHud.so"
if [[ ! -f "$LIB" || "$LIB" -ot "build/meson64/src/libMangoHud.so" ]]; then
build
@ -203,37 +208,67 @@ install() {
[ "$UID" -eq 0 ] || exec $SU_CMD bash "$0" install
uninstall
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib/libMangoHud.so /usr/lib/mangohud/lib/libMangoHud.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_dlsym.so /usr/lib/mangohud/lib32/libMangoHud_dlsym.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib/libMangoHud_dlsym.so /usr/lib/mangohud/lib/libMangoHud_dlsym.so
DEFAULTLIB=lib32
for i in $DISTRO; do
case $i in
*arch*)
DEFAULTLIB=lib64
;;
esac
done
if [ "$MACHINE" != "x86_64" ]; then
# Native libs
DEFAULTLIB=lib64
fi
echo DEFAULTLIB: $DEFAULTLIB
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud_dlsym.so /usr/lib/mangohud/lib64/libMangoHud_dlsym.so
if [ "$MACHINE" = "x86_64" ]; then
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so
/usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_dlsym.so /usr/lib/mangohud/lib32/libMangoHud_dlsym.so
fi
/usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.json /usr/share/vulkan/implicit_layer.d/MangoHud.json
/usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.json /usr/share/vulkan/implicit_layer.d/MangoHud.json
/usr/bin/install -Dvm644 ./build/release/usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1
/usr/bin/install -Dvm644 ./build/release/usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example
/usr/bin/install -vm755 ./build/release/usr/bin/mangohud /usr/bin/mangohud
ln -sv $DEFAULTLIB /usr/lib/mangohud/lib
# FIXME get the triplet somehow
ln -sv lib64 /usr/lib/mangohud/x86_64
ln -sv lib64 /usr/lib/mangohud/x86_64-linux-gnu
ln -sv . /usr/lib/mangohud/lib64/x86_64
ln -sv . /usr/lib/mangohud/lib64/x86_64-linux-gnu
ln -sv lib32 /usr/lib/mangohud/i686
ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu
ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu
mkdir -p /usr/lib/mangohud/tls
ln -sv ../lib /usr/lib/mangohud/tls/x86_64
ln -sv ../lib64 /usr/lib/mangohud/tls/x86_64
ln -sv ../lib32 /usr/lib/mangohud/tls/i686
# Some distros search in $prefix/x86_64-linux-gnu/tls/x86_64 etc instead
ln -sv . /usr/lib/mangohud/lib/i686-linux-gnu
ln -sv . /usr/lib/mangohud/lib/x86_64-linux-gnu
if [ ! -e /usr/lib/mangohud/lib/i386-linux-gnu ]; then
ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu
fi
if [ ! -e /usr/lib/mangohud/lib/i686-linux-gnu ]; then
ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu
fi
if [ ! -e /usr/lib/mangohud/lib/x86_64-linux-gnu ]; then
ln -sv ../lib64 /usr/lib/mangohud/lib/x86_64-linux-gnu
fi
# $LIB can be "lib/tls/x86_64"?
ln -sv ../tls /usr/lib/mangohud/lib/tls
ln -sv lib /usr/lib/mangohud/lib64
ln -sv lib /usr/lib/mangohud/x86_64
ln -sv lib /usr/lib/mangohud/x86_64-linux-gnu
ln -sv . /usr/lib/mangohud/lib/x86_64
ln -sv lib32 /usr/lib/mangohud/i686
ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu
ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu
ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu
ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu
#ln -sv lib /usr/lib/mangohud/aarch64-linux-gnu
#ln -sv lib /usr/lib/mangohud/arm-linux-gnueabihf
#ln -sv lib64 /usr/lib/mangohud/aarch64-linux-gnu
#ln -sv lib64 /usr/lib/mangohud/arm-linux-gnueabihf
echo "MangoHud Installed"
}
@ -294,6 +329,7 @@ while [ $# -gt 0 ]; do
"pull") git pull ${OPTS[@]};;
"configure") configure ${OPTS[@]};;
"build") build ${OPTS[@]};;
"build_dbg") build --buildtype=debug -Dglibcxx_asserts=true ${OPTS[@]};;
"package") package;;
"install") install;;
"reinstall") reinstall;;

@ -2,6 +2,7 @@ project('MangoHud',
['c', 'cpp'],
version : 'v0.6.5',
license : 'MIT',
meson_version: '>=0.54.0',
default_options : ['buildtype=release', 'c_std=c99', 'cpp_std=c++14']
)
@ -20,13 +21,16 @@ pre_args = [
'-D__STDC_FORMAT_MACROS',
'-D__STDC_LIMIT_MACROS',
'-DPACKAGE_VERSION="@0@"'.format(meson.project_version()),
'-DSPDLOG_COMPILED_LIB'
]
# 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 += '-DNDEBUG'
pre_args += '-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_' + get_option('loglevel').to_upper()
endif
# TODO: this is very incomplete
@ -84,10 +88,14 @@ 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_libdrm = dependency('libdrm', required: get_option('with_libdrm_amdgpu')).partial_dependency(compile_args : true, includes : true)
# dep_libdrm_amdgpu = dependency('libdrm_amdgpu', version : '>=2.4.79', required: get_option('with_libdrm_amdgpu')).partial_dependency(compile_args : true, includes : true)
else
dep_x11 = null_dep
dep_wayland_client = null_dep
dbus_dep = null_dep
dep_libdrm = null_dep
# dep_libdrm_amdgpu = null_dep
endif
if dep_x11.found()
@ -238,6 +246,17 @@ dearimgui_sp = subproject('imgui', default_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',
])
spdlog_dep = spdlog_sp.get_variable('spdlog_dep')
else
spdlog_dep = dependency('spdlog', required: true)
endif
if ['windows', 'mingw'].contains(host_machine.system())
subdir('modules/minhook')
inc_common += ( include_directories('modules/minhook/include'))

@ -1,5 +1,6 @@
option('glibcxx_asserts', type : 'boolean', value : false)
option('use_system_vulkan', type : 'feature', value : 'disabled', description: 'Use system vulkan headers instead of the provided ones')
option('use_system_spdlog', type : 'feature', value : 'disabled', description: 'Use system spdlog library')
option('vulkan_datadir', type : 'string', value : '', description: 'Path to the system vulkan headers data directory if different from MangoHud\'s datadir')
option('append_libdir_mangohud', type : 'boolean', value : true, description: 'Append "mangohud" to libdir path or not.')
option('ld_libdir_prefix', type : 'boolean', value : false, description: 'Set ld libdir to "$prefix/lib/mangohud/\$LIB"')
@ -12,3 +13,5 @@ option('with_x11', type : 'feature', value : 'enabled')
option('with_wayland', type : 'feature', value : 'disabled')
option('with_dbus', type : 'feature', value : 'enabled')
option('with_dlsym', type : 'feature', value : 'disabled')
option('with_libdrm_amdgpu', type : 'feature', value : 'enabled', description: 'Get amdgpu sensor info through libdrm_amdgpu')
option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build')

@ -0,0 +1,56 @@
/*
Inspired by radeontop
*/
#include "auth.h"
#include <xcb/xcb.h>
#include <xcb/dri2.h>
#include <xf86drm.h>
#include <libdrm/amdgpu_drm.h>
#include <libdrm/amdgpu.h>
#include <cstdlib>
#include <cstdio>
/* Try to authenticate the DRM client with help from the X server. */
bool authenticate_drm_xcb(drm_magic_t magic) {
xcb_connection_t *conn = xcb_connect(NULL, NULL);
if (!conn) {
return false;
}
if (xcb_connection_has_error(conn)) {
xcb_disconnect(conn);
return false;
}
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
xcb_window_t window = screen->root;
/* Authenticate our client via the X server using the magic. */
xcb_dri2_authenticate_cookie_t auth_cookie =
xcb_dri2_authenticate(conn, window, magic);
xcb_dri2_authenticate_reply_t *auth_reply =
xcb_dri2_authenticate_reply(conn, auth_cookie, NULL);
free(auth_reply);
xcb_disconnect(conn);
return true;
}
bool authenticate_drm(int fd) {
drm_magic_t magic;
/* Obtain magic for our DRM client. */
if (drmGetMagic(fd, &magic) < 0) {
return false;
}
/* Try self-authenticate (if we are somehow the master). */
if (drmAuthMagic(fd, magic) == 0) {
if (drmDropMaster(fd)) {
perror("MANGOHUD: Failed to drop DRM master");
fprintf(stderr, "\n\tWARNING: other DRM clients will crash on VT switch\n");
}
return true;
}
return authenticate_drm_xcb(magic);
}

@ -0,0 +1,5 @@
#pragma once
#include <libdrm/drm.h>
bool authenticate_drm_xcb(drm_magic_t magic);
bool authenticate_drm(int fd);

@ -1,8 +1,9 @@
#include <stdio.h>
#include "battery.h"
#include <spdlog/spdlog.h>
#include <filesystem.h>
#include "battery.h"
namespace fs = ghc::filesystem;
using namespace std;
void BatteryStats::numBattery() {
int batteryCount = 0;
@ -21,19 +22,18 @@ void BatteryStats::numBattery() {
batt_check = true;
}
void BatteryStats::update() {
if (!batt_check) {
numBattery();
if (batt_count == 0) {
std::cerr<<"MANGOHUD: No battery found\n";
SPDLOG_ERROR("No battery found");
}
}
if (batt_count > 0) {
current_watt = getPower();
current_percent = getPercent();
}
current_watt = getPower();
current_percent = getPercent();
}
}
float BatteryStats::getPercent()
@ -58,7 +58,6 @@ float BatteryStats::getPercent()
if(std::getline(input2, line)) {
charge_f += (stof(line) / 1000000);
}
}
else if (fs::exists(energy_now)) {
@ -71,7 +70,6 @@ float BatteryStats::getPercent()
if(std::getline(input2, line)) {
charge_f += (stof(line) / 1000000);
}
}
else {
@ -106,7 +104,7 @@ float BatteryStats::getPower() {
}
if (state[i] == "Charging" || state[i] == "Unknown") {
return 0;
return 0;
}
if (fs::exists(current_power)) {

@ -1,10 +1,5 @@
#pragma once
#include "overlay.h"
#include "overlay_params.h"
#include <logging.h>
#include <vector>
#include <unordered_map>
#include <filesystem.h>
#include <string>
class BatteryStats{
public:
@ -12,11 +7,11 @@ class BatteryStats{
void update();
float getPower();
float getPercent();
string battPath[2];
std::string battPath[2];
float current_watt = 0;
float current_percent = 0;
string current_status="";
string state [2];
std::string current_status;
std::string state [2];
int batt_count=0;
bool batt_check = false;

@ -12,8 +12,7 @@ static std::string get_proc_name() {
if (!proc_name.empty()) {
return proc_name;
}
const std::string p = get_exe_path();
return p.substr(p.find_last_of("/\\") + 1);
return get_basename(get_exe_path());
}
static std::vector<std::string> blacklist {

@ -5,6 +5,7 @@
#include <thread>
#include <unordered_map>
#include <string>
#include <spdlog/spdlog.h>
#include "config.h"
#include "file_utils.h"
#include "string_utils.h"
@ -110,17 +111,16 @@ void parseConfigFile(overlay_params& params) {
std::ifstream stream(*p);
if (!stream.good()) {
// printing just so user has an idea of possible configs
std::cerr << "skipping config: " << *p << " [ not found ]" << std::endl;
SPDLOG_INFO("skipping config: '{}' [ not found ]", *p);
continue;
}
stream.imbue(std::locale::classic());
std::cerr << "parsing config: " << *p;
SPDLOG_INFO("parsing config: '{}'", *p);
while (std::getline(stream, line))
{
parseConfigLine(line, params.options);
}
std::cerr << " [ ok ]" << std::endl;
params.config_file_path = *p;
return;
}

@ -9,6 +9,7 @@
#include <algorithm>
#include <regex>
#include <inttypes.h>
#include <spdlog/spdlog.h>
#include "string_utils.h"
#ifndef PROCDIR
@ -116,13 +117,13 @@ bool CPUStats::Init()
m_cpuData.clear();
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
SPDLOG_ERROR("Failed to opening " PROCSTATFILE);
return false;
}
do {
if (!std::getline(file, line)) {
std::cerr << "Failed to read all of " << PROCSTATFILE << std::endl;
SPDLOG_DEBUG("Failed to read all of " PROCSTATFILE);
return false;
} else if (starts_with(line, "cpu")) {
if (first) {
@ -175,7 +176,7 @@ bool CPUStats::UpdateCPUData()
bool ret = false;
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
SPDLOG_ERROR("Failed to opening " PROCSTATFILE);
return false;
}
@ -189,21 +190,20 @@ bool CPUStats::UpdateCPUData()
} else if (sscanf(line.c_str(), "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
&cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 11) {
//std::cerr << "Parsing 'cpu" << cpuid << "' line:" << line << std::endl;
//SPDLOG_DEBUG("Parsing 'cpu{}' line:{}", cpuid, line);
if (!ret) {
//std::cerr << "Failed to parse 'cpu' line" << std::endl;
std::cerr << "Failed to parse 'cpu' line:" << line << std::endl;
SPDLOG_DEBUG("Failed to parse 'cpu' line:{}", line);
return false;
}
if (cpuid < 0 /* can it? */) {
std::cerr << "Cpu id '" << cpuid << "' is out of bounds" << std::endl;
SPDLOG_DEBUG("Cpu id '{}' is out of bounds", cpuid);
return false;
}
if ((size_t)cpuid >= m_cpuData.size()) {
std::cerr << "Cpu id '" << cpuid << "' is out of bounds, reiniting" << std::endl;
SPDLOG_DEBUG("Cpu id '{}' is out of bounds, reiniting", cpuid);
return Reinit();
}
@ -399,9 +399,7 @@ static bool find_fallback_temp_input(const std::string path, std::string& input)
if (!ends_with(file, "_input"))
continue;
input = path + "/" + file;
#ifndef NDEBUG
std::cerr << "fallback cpu temp input: " << input << "\n";
#endif
SPDLOG_DEBUG("fallback cpu temp input: {}", input);
return true;
}
return false;
@ -418,9 +416,8 @@ bool CPUStats::GetCpuFile() {
for (auto& dir : dirs) {
path = hwmon + dir;
name = read_line(path + "/name");
#ifndef NDEBUG
std::cerr << "hwmon: sensor name: " << name << std::endl;
#endif
SPDLOG_DEBUG("hwmon: sensor name: {}", name);
if (name == "coretemp") {
find_temp_input(path, input, "Package id 0");
break;
@ -437,12 +434,11 @@ bool CPUStats::GetCpuFile() {
}
if (path.empty() || (!file_exists(input) && !find_fallback_temp_input(path, input))) {
std::cerr << "MANGOHUD: Could not find cpu temp sensor location" << std::endl;
SPDLOG_ERROR("Could not find cpu temp sensor location");
return false;
} else {
#ifndef NDEBUG
std::cerr << "hwmon: using input: " << input << std::endl;
#endif
SPDLOG_DEBUG("hwmon: using input: {}", input);
m_cpuTempFile = fopen(input.c_str(), "r");
}
return true;
@ -480,12 +476,10 @@ CPUPowerData_k10temp* init_cpu_power_data_k10temp(const std::string path) {
if(!find_input(path, "in", socVoltageInput, "Vsoc")) return nullptr;
if(!find_input(path, "curr", socCurrentInput, "Isoc")) return nullptr;
#ifndef NDEBUG
std::cerr << "hwmon: using input: " << coreVoltageInput << std::endl;
std::cerr << "hwmon: using input: " << coreCurrentInput << std::endl;
std::cerr << "hwmon: using input: " << socVoltageInput << std::endl;
std::cerr << "hwmon: using input: " << socCurrentInput << std::endl;
#endif
SPDLOG_DEBUG("hwmon: using input: {}", coreVoltageInput);
SPDLOG_DEBUG("hwmon: using input: {}", coreCurrentInput);
SPDLOG_DEBUG("hwmon: using input: {}", socVoltageInput);
SPDLOG_DEBUG("hwmon: using input: {}", socCurrentInput);
powerData->coreVoltageFile = fopen(coreVoltageInput.c_str(), "r");
powerData->coreCurrentFile = fopen(coreCurrentInput.c_str(), "r");
@ -503,10 +497,8 @@ CPUPowerData_zenpower* init_cpu_power_data_zenpower(const std::string path) {
if(!find_input(path, "power", corePowerInput, "SVI2_P_Core")) return nullptr;
if(!find_input(path, "power", socPowerInput, "SVI2_P_SoC")) return nullptr;
#ifndef NDEBUG
std::cerr << "hwmon: using input: " << corePowerInput << std::endl;
std::cerr << "hwmon: using input: " << socPowerInput << std::endl;
#endif
SPDLOG_DEBUG("hwmon: using input: {}", corePowerInput);
SPDLOG_DEBUG("hwmon: using input: {}", socPowerInput);
powerData->corePowerFile = fopen(corePowerInput.c_str(), "r");
powerData->socPowerFile = fopen(socPowerInput.c_str(), "r");
@ -538,9 +530,8 @@ bool CPUStats::InitCpuPowerData() {
for (auto& dir : dirs) {
path = hwmon + dir;
name = read_line(path + "/name");
#ifndef NDEBUG
std::cerr << "hwmon: sensor name: " << name << std::endl;
#endif
SPDLOG_DEBUG("hwmon: sensor name: {}", name);
if (name == "k10temp") {
cpuPowerData = (CPUPowerData*)init_cpu_power_data_k10temp(path);
break;
@ -556,9 +547,7 @@ bool CPUStats::InitCpuPowerData() {
for (auto& dir : powercap_dirs) {
path = powercap + dir;
name = read_line(path + "/name");
#ifndef NDEBUG
std::cerr << "powercap: name: " << name << std::endl;
#endif
SPDLOG_DEBUG("powercap: name: {}", name);
if (name == "package-0") {
cpuPowerData = (CPUPowerData*)init_cpu_power_data_rapl(path);
break;
@ -567,7 +556,7 @@ bool CPUStats::InitCpuPowerData() {
}
if(cpuPowerData == nullptr) {
std::cerr << "MANGOHUD: Failed to initialize CPU power data" << std::endl;
SPDLOG_ERROR("Failed to initialize CPU power data");
return false;
}

@ -150,20 +150,9 @@ bool dbus_manager::get_media_player_metadata(metadata& meta, std::string name) {
return true;
}
bool dbus_manager::init(const std::string& requested_player) {
if (!requested_player.empty()) {
m_requested_player = "org.mpris.MediaPlayer2." + requested_player;
} else
m_requested_player.clear();
if (m_inited) {
select_active_player();
return true;
}
bool dbus_manager::init_internal() {
if (!m_dbus_ldr.IsLoaded() && !m_dbus_ldr.Load("libdbus-1.so.3")) {
std::cerr << "MANGOHUD: Could not load libdbus-1.so.3\n";
SPDLOG_ERROR("Could not load libdbus-1.so.3");
return false;
}
@ -173,23 +162,48 @@ bool dbus_manager::init(const std::string& requested_player) {
if (nullptr ==
(m_dbus_conn = m_dbus_ldr.bus_get(DBUS_BUS_SESSION, &m_error))) {
std::cerr << "MANGOHUD: " << m_error.message << std::endl;
SPDLOG_ERROR("{}", m_error.message);
m_dbus_ldr.error_free(&m_error);
return false;
}
std::cout << "MANGOHUD: Connected to D-Bus as \""
<< m_dbus_ldr.bus_get_unique_name(m_dbus_conn) << "\"."
<< std::endl;
SPDLOG_DEBUG("Connected to D-Bus as \"{}\"",
m_dbus_ldr.bus_get_unique_name(m_dbus_conn));
dbus_list_name_to_owner();
connect_to_signals();
select_active_player();
m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals,
reinterpret_cast<void*>(this), nullptr);
start_thread();
dbus_list_name_to_owner();
m_inited = true;
return true;
}
bool dbus_manager::init(Service srv) {
if (!m_inited && !init_internal())
return false;
connect_to_signals(srv);
m_active_srvs |= srv;
return true;
}
bool dbus_manager::init_mpris(const std::string& requested_player) {
if (!requested_player.empty()) {
m_requested_player = "org.mpris.MediaPlayer2." + requested_player;
} else
m_requested_player.clear();
if (m_active_srvs & SRV_MPRIS) {
select_active_player();
return true;
}
SPDLOG_WARN("D-Bus hasn't been inited yet.");
return false;
}
bool dbus_manager::select_active_player() {
auto old_active_player = m_active_player;
m_active_player = "";
@ -198,10 +212,7 @@ bool dbus_manager::select_active_player() {
// If the requested player is available, use it
if (m_name_owners.count(m_requested_player) > 0) {
m_active_player = m_requested_player;
#ifndef NDEBUG
std::cerr << "Selecting requested player: " << m_requested_player
<< "\n";
#endif
SPDLOG_DEBUG("Selecting requested player: {}", m_requested_player);
get_media_player_metadata(meta, m_active_player);
}
} else {
@ -221,9 +232,7 @@ bool dbus_manager::select_active_player() {
if(it != m_name_owners.end()){
m_active_player = it->first;
#ifndef NDEBUG
std::cerr << "Selecting fallback player: " << m_active_player << "\n";
#endif
SPDLOG_DEBUG("Selecting fallback player: {}", m_active_player);
}
}
}
@ -232,9 +241,7 @@ bool dbus_manager::select_active_player() {
onNewPlayer(meta);
return true;
} else {
#ifndef NDEBUG
std::cerr << "No active players\n";
#endif
SPDLOG_DEBUG("No active players");
if (!old_active_player.empty()) {
onNoPlayer();
}
@ -242,20 +249,26 @@ bool dbus_manager::select_active_player() {
}
}
void dbus_manager::deinit() {
void dbus_manager::deinit(Service srv) {
if (!m_inited) return;
m_active_srvs &= ~srv;
if (m_dbus_conn)
disconnect_from_signals(srv);
// unreference system bus connection instead of closing it
if (m_dbus_conn) {
disconnect_from_signals();
if (m_dbus_conn && !m_active_srvs) {
m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals,
reinterpret_cast<void*>(this));
stop_thread();
m_dbus_ldr.connection_unref(m_dbus_conn);
m_dbus_conn = nullptr;
m_dbus_ldr.error_free(&m_error);
m_inited = false;
}
m_dbus_ldr.error_free(&m_error);
m_inited = false;
}
dbus_manager::~dbus_manager() { deinit(); }
dbus_manager::~dbus_manager() { deinit(SRV_ALL); }
DBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn,
DBusMessage* msg,
@ -328,37 +341,66 @@ bool dbus_manager::handle_name_owner_changed(DBusMessage* _msg,
return true;
}
void dbus_manager::connect_to_signals() {
bool dbus_manager::gamemode_enabled(int32_t pid) {
if (!m_inited)
return false;
auto reply =
DBusMessage_wrap::new_method_call(
"com.feralinteractive.GameMode", "/com/feralinteractive/GameMode",
"com.feralinteractive.GameMode", "QueryStatus", &dbus_mgr.dbus())
.argument(pid)
.send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
if (!reply) return false;
auto iter = reply.iter();
if (!iter.is_signed()) return false;
return !!iter.get_primitive<int32_t>();
}
bool dbus_manager::handle_game_registered(DBusMessage* _msg,
const char* sender) {
auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr);
auto pid = iter.get_primitive<int32_t>();
iter.next();
auto path = iter.get_primitive<std::string>();
SPDLOG_INFO("Game registered: {} '{}'", pid, path);
return true;
}
bool dbus_manager::handle_game_unregistered(DBusMessage* _msg,
const char* sender) {
auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr);
auto pid = iter.get_primitive<int32_t>();
iter.next();
auto path = iter.get_primitive<std::string>();
SPDLOG_INFO("Game unregistered: {} '{}'", pid, path);
return true;
}
void dbus_manager::connect_to_signals(Service srv) {
for (auto kv : m_signals) {
if (!(kv.srv & srv)) continue;
auto signal = format_signal(kv);
m_dbus_ldr.bus_add_match(m_dbus_conn, signal.c_str(), &m_error);
if (m_dbus_ldr.error_is_set(&m_error)) {
::perror(m_error.name);
::perror(m_error.message);
SPDLOG_ERROR("{}: {}", m_error.name, m_error.message);
m_dbus_ldr.error_free(&m_error);
// return;
}
}
m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals,
reinterpret_cast<void*>(this), nullptr);
start_thread();
}
void dbus_manager::disconnect_from_signals() {
m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals,
reinterpret_cast<void*>(this));
void dbus_manager::disconnect_from_signals(Service srv) {
for (auto kv : m_signals) {
if (!(kv.srv & srv)) continue;
auto signal = format_signal(kv);
m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error);
if (m_dbus_ldr.error_is_set(&m_error)) {
::perror(m_error.name);
::perror(m_error.message);
SPDLOG_ERROR("{}: {}", m_error.name, m_error.message);
m_dbus_ldr.error_free(&m_error);
}
}
stop_thread();
}
bool dbus_manager::dbus_list_name_to_owner() {
@ -375,7 +417,7 @@ bool dbus_manager::dbus_list_name_to_owner() {
return false;
}
iter.array_for_each_value<std::string>([&](std::string name) {
if (!starts_with(name.c_str(), "org.mpris.MediaPlayer2.")) return;
if (!starts_with(name, "org.mpris.MediaPlayer2.")) return;
std::string owner;
if (dbus_get_name_owner(dbus_mgr, owner, name.c_str())) {
m_name_owners[name] = owner;

@ -3,6 +3,8 @@
#define MANGOHUD_DBUS_HELPERS
#include <vector>
#include <spdlog/spdlog.h>
#include <signal.h>
#include "loaders/loader_dbus.h"
@ -26,7 +28,7 @@ template <class T>
const int dbus_type_identifier = dbus_type_traits<T>().value;
template <class T>
const bool is_fixed = dbus_type_traits<T>().is_fiexd;
const bool is_fixed = dbus_type_traits<T>().is_fixed;
} // namespace detail
class DBusMessageIter_wrap {
@ -135,14 +137,16 @@ bool DBusMessageIter_wrap::is_array() const noexcept {
template <class T>
auto DBusMessageIter_wrap::get_primitive() -> T {
auto requested_type = detail::dbus_type_identifier<T>;
if (requested_type != type()) {
std::cerr << "Type mismatch: '" << ((char)requested_type) << "' vs '"
<< (char)type() << "'\n";
if (type() == DBUS_TYPE_OBJECT_PATH && requested_type == DBUS_TYPE_STRING) {
// no special type, just a string
}
else if (requested_type != type()) {
SPDLOG_ERROR("Type mismatch: '{}' vs '{}'",
((char)requested_type), (char)type());
#ifndef NDEBUG
exit(-1);
#else
return T();
raise(SIGTRAP);
#endif
return T();
}
T ret;
@ -152,7 +156,10 @@ auto DBusMessageIter_wrap::get_primitive() -> T {
template <>
auto DBusMessageIter_wrap::get_primitive<std::string>() -> std::string {
return std::string(get_primitive<const char*>());
auto s = get_primitive<const char*>();
if (!s)
return std::string();
return std::string(s);
}
uint64_t DBusMessageIter_wrap::get_unsigned() {
@ -190,13 +197,13 @@ auto DBusMessageIter_wrap::get_stringified() -> std::string {
if (is_unsigned()) return std::to_string(get_unsigned());
if (is_signed()) return std::to_string(get_signed());
if (is_double()) return std::to_string(get_primitive<double>());
std::cerr << "stringify failed\n";
SPDLOG_ERROR("stringify failed");
return std::string();
}
auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap {
if (!is_array()) {
std::cerr << "Not an array; " << (char)type() << "\n";
SPDLOG_ERROR("Not an array; {}", (char)type());
return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);
}
@ -207,7 +214,7 @@ auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap {
auto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap {
if (type() != DBUS_TYPE_DICT_ENTRY) {
std::cerr << "Not a dict entry" << (char)type() << "\n";
SPDLOG_ERROR("Not a dict entry {}", (char)type());
return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);
}
@ -334,7 +341,7 @@ DBusMessage_wrap DBusMessage_wrap::send_with_reply_and_block(
auto reply = m_DBus->connection_send_with_reply_and_block(conn, m_msg,
timeout, &err);
if (reply == nullptr) {
std::cerr << "MangoHud[" << __func__ << "]: " << err.message << "\n";
SPDLOG_ERROR("[{}]: {}", __func__, err.message);
free_if_owning();
m_DBus->error_free(&err);
}

@ -28,6 +28,12 @@ struct metadata {
bool got_playback_data = false;
};
struct mp_fmt
{
std::string text;
float width;
};
struct mutexed_metadata {
std::mutex mtx;
metadata meta;
@ -37,9 +43,7 @@ struct mutexed_metadata {
int dir = -1;
bool needs_recalc = true;
float tw0;
float tw1;
float tw2;
std::vector<mp_fmt> formatted;
} ticker;
};
@ -55,7 +59,16 @@ namespace dbusmgr {
class dbus_manager;
using signal_handler_func = bool (dbus_manager::*)(DBusMessage*, const char*);
enum Service
{
SRV_NONE = 0,
SRV_MPRIS = (1ul << 0),
SRV_GAMEMODE = (1ul << 1),
SRV_ALL = 0xFFFFFFFF,
};
struct DBusSignal {
Service srv;
const char* intf;
const char* signal;
signal_handler_func handler;
@ -67,16 +80,20 @@ class dbus_manager {
~dbus_manager();
bool init(const std::string& requested_player);
void deinit();
bool init(Service srv);
bool init_mpris(const std::string& requested_player);
void deinit(Service srv);
bool get_media_player_metadata(metadata& meta, std::string name = "");
void connect_to_signals();
void disconnect_from_signals();
void connect_to_signals(Service srv);
void disconnect_from_signals(Service srv);
DBusConnection* get_conn() const { return m_dbus_conn; }
bool gamemode_enabled(int32_t pid);
libdbus_loader& dbus() { return m_dbus_ldr; }
protected:
bool init_internal();
void stop_thread();
void start_thread();
void dbus_thread();
@ -89,6 +106,8 @@ class dbus_manager {
bool handle_properties_changed(DBusMessage*, const char*);
bool handle_name_owner_changed(DBusMessage*, const char*);
bool handle_game_registered(DBusMessage*, const char*);
bool handle_game_unregistered(DBusMessage*, const char*);
void onNewPlayer(
metadata& meta); // A different player has become the active player
@ -105,12 +124,17 @@ class dbus_manager {
std::unordered_map<std::string, std::string> m_name_owners;
std::string m_requested_player;
std::string m_active_player;
uint32_t m_active_srvs = SRV_NONE;
const std::array<DBusSignal, 2> m_signals{{
{"org.freedesktop.DBus", "NameOwnerChanged",
{SRV_MPRIS, "org.freedesktop.DBus", "NameOwnerChanged",
&dbus_manager::handle_name_owner_changed},
{"org.freedesktop.DBus.Properties", "PropertiesChanged",
{SRV_MPRIS, "org.freedesktop.DBus.Properties", "PropertiesChanged",
&dbus_manager::handle_properties_changed},
// {SRV_GAMEMODE, "com.feralinteractive.GameMode", "GameRegistered",
// &dbus_manager::handle_game_registered},
// {SRV_GAMEMODE, "com.feralinteractive.GameMode", "GameUnregistered",
// &dbus_manager::handle_game_unregistered},
}};
};

@ -8,6 +8,7 @@
#include <fstream>
#include <cstring>
#include <string>
#include <spdlog/spdlog.h>
std::string read_line(const std::string& filename)
{
@ -17,13 +18,25 @@ std::string read_line(const std::string& filename)
return line;
}
std::string get_basename(const std::string&& path)
{
auto npos = path.find_last_of("/\\");
if (npos == std::string::npos)
return path;
if (npos < path.size() - 1)
return path.substr(npos + 1);
return path;
}
#ifdef __gnu_linux__
bool find_folder(const char* root, const char* prefix, std::string& dest)
{
struct dirent* dp;
DIR* dirp = opendir(root);
if (!dirp) {
std::cerr << "Error opening directory '" << root << "': ";
perror("");
SPDLOG_ERROR("Error opening directory '{}': {}", root, strerror(errno));
return false;
}
@ -52,8 +65,7 @@ std::vector<std::string> ls(const char* root, const char* prefix, LS_FLAGS flags
DIR* dirp = opendir(root);
if (!dirp) {
std::cerr << "Error opening directory '" << root << "': ";
perror("");
SPDLOG_ERROR("Error opening directory '{}': {}", root, strerror(errno));
return list;
}
@ -107,6 +119,11 @@ std::string read_symlink(const char * link)
return std::string(result, (count > 0) ? count : 0);
}
std::string read_symlink(const std::string&& link)
{
return read_symlink(link.c_str());
}
std::string get_exe_path()
{
return read_symlink("/proc/self/exe");
@ -181,3 +198,5 @@ std::string get_config_dir()
path += "/.config";
return path;
}
#endif // __gnu_linux__

@ -19,6 +19,8 @@ std::vector<std::string> ls(const char* root, const char* prefix = nullptr, LS_F
bool file_exists(const std::string& path);
bool dir_exists(const std::string& path);
std::string read_symlink(const char * link);
std::string read_symlink(const std::string&& link);
std::string get_basename(const std::string&& path); //prefix so it doesn't conflict libgen
std::string get_exe_path();
std::string get_wine_exe_name(bool keep_ext = false);
std::string get_home_dir();

@ -3,14 +3,6 @@
#include <fstream>
#include <string>
std::string read_line(const std::string& filename)
{
std::string line;
std::ifstream file(filename);
std::getline(file, line);
return line;
}
bool find_folder(const char* root, const char* prefix, std::string& dest)
{
return false;

@ -3,6 +3,7 @@
#include <thread>
#include <string>
#include <iostream>
#include <sstream>
#include <memory>
#include <unistd.h>
#include <imgui.h>
@ -71,6 +72,7 @@ void imgui_init()
return;
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
_params = params;
//check for blacklist item in the config file
for (auto& item : params.blacklist) {
@ -168,10 +170,6 @@ void imgui_create(void *ctx)
void imgui_shutdown()
{
#ifndef NDEBUG
std::cerr << __func__ << std::endl;
#endif
if (state.imgui_ctx) {
ImGui::SetCurrentContext(state.imgui_ctx);
ImGui_ImplOpenGL3_Shutdown();
@ -185,10 +183,6 @@ void imgui_set_context(void *ctx)
{
if (!ctx)
return;
#ifndef NDEBUG
std::cerr << __func__ << ": " << ctx << std::endl;
#endif
imgui_create(ctx);
}

@ -64,12 +64,14 @@
// ES 3.0 300 "#version 300 es" = WebGL 2.0
//----------------------------------------
#include <spdlog/spdlog.h>
#include <imgui.h>
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <stdint.h> // intptr_t
#include <sstream>
#include <spdlog/spdlog.h>
#include <glad/glad.h>
#include "overlay.h"
@ -138,13 +140,13 @@ static bool CheckShader(GLuint handle, const char* desc)
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
SPDLOG_ERROR("ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile {}!", desc);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
SPDLOG_ERROR("{}", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
@ -156,13 +158,13 @@ static bool CheckProgram(GLuint handle, const char* desc)
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
SPDLOG_ERROR("ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link {}! (with GLSL '{}')", desc, g_GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
SPDLOG_ERROR("{}", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
@ -284,7 +286,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"}\n";
#ifndef NDEBUG
printf("glsl_version: %d\n", glsl_version);
fprintf(stderr, "glsl_version: %d\n", glsl_version);
#endif
// Select shaders matching our GLSL versions
const GLchar* vertex_shader = NULL;
@ -363,7 +365,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
static void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
#ifndef NDEBUG
printf("%s\n", __func__);
fprintf(stderr, "%s\n", __func__);
#endif
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
@ -413,7 +415,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
GLint major = 0, minor = 0;
GetOpenGLVersion(major, minor, g_IsGLES);
printf("Version: %d.%d %s\n", major, minor, g_IsGLES ? "ES" : "");
SPDLOG_INFO("GL version: {}.{} {}", major, minor, g_IsGLES ? "ES" : "");
if (!g_IsGLES) {
// Not GL ES
@ -478,16 +480,12 @@ void ImGui_ImplOpenGL3_NewFrame()
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
else if (!glIsProgram(g_ShaderHandle)) { // TODO Got created in a now dead context?
#ifndef NDEBUG
fprintf(stderr, "MANGOHUD: recreating lost objects\n");
#endif
SPDLOG_DEBUG("Recreating lost objects");
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
if (!glIsTexture(g_FontTexture)) {
#ifndef NDEBUG
fprintf(stderr, "MANGOHUD: GL Texture lost? Regenerating.\n");
#endif
SPDLOG_DEBUG("GL Texture lost? Regenerating.");
g_FontTexture = 0;
ImGui_ImplOpenGL3_CreateFontsTexture();
}

@ -2,14 +2,13 @@
#include <array>
#include <cstring>
#include <dlfcn.h>
#include <chrono>
#include <iomanip>
#include <spdlog/spdlog.h>
#include "real_dlsym.h"
#include "mesa/util/macros.h"
#include "mesa/util/os_time.h"
#include "blacklist.h"
#include <chrono>
#include <iomanip>
#include "imgui_hud.h"
using namespace MangoHud::GL;
@ -23,7 +22,7 @@ void* get_egl_proc_address(const char* name) {
if (!pfn_eglGetProcAddress) {
void *handle = real_dlopen("libEGL.so.1", RTLD_LAZY|RTLD_LOCAL);
if (!handle) {
std::cerr << "MANGOHUD: Failed to open " << "" MANGOHUD_ARCH << " libEGL.so.1: " << dlerror() << std::endl;
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libEGL.so.1: {}", dlerror());
} else {
pfn_eglGetProcAddress = reinterpret_cast<decltype(pfn_eglGetProcAddress)>(real_dlsym(handle, "eglGetProcAddress"));
}
@ -36,7 +35,7 @@ void* get_egl_proc_address(const char* name) {
func = get_proc_address( name );
if (!func) {
std::cerr << "MANGOHUD: Failed to get function '" << name << "'" << std::endl;
SPDLOG_DEBUG("Failed to get function '{}'", name);
}
return func;
@ -44,10 +43,7 @@ void* get_egl_proc_address(const char* name) {
//EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EXPORT_C_(int) eglMakeCurrent_OFF(void *dpy, void *draw, void *read,void *ctx) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << draw << ", " << ctx << std::endl;
#endif
SPDLOG_TRACE("{}: draw: {}, ctx: {}", __func__, draw, ctx);
int ret = 0;
return ret;
}
@ -63,9 +59,6 @@ EXPORT_C_(unsigned int) eglSwapBuffers( void* dpy, void* surf)
if (!pfn_eglQuerySurface)
pfn_eglQuerySurface = reinterpret_cast<decltype(pfn_eglQuerySurface)>(get_egl_proc_address("eglQuerySurface"));
//std::cerr << __func__ << "\n";
imgui_create(surf);
int width=0, height=0;
@ -73,7 +66,6 @@ EXPORT_C_(unsigned int) eglSwapBuffers( void* dpy, void* surf)
pfn_eglQuerySurface(dpy, surf, 0x3057, &width))
imgui_render(width, height);
//std::cerr << "\t" << width << " x " << height << "\n";
using namespace std::chrono_literals;
if (fps_limit_stats.targetFrameTime > 0s){
fps_limit_stats.frameStart = Clock::now();
@ -111,10 +103,9 @@ EXPORT_C_(void *) mangohud_find_egl_ptr(const char *name)
}
EXPORT_C_(void *) eglGetProcAddress(const char* procName) {
//std::cerr << __func__ << ": " << procName << std::endl;
void* real_func = get_egl_proc_address(procName);
void* func = mangohud_find_egl_ptr(procName);
SPDLOG_TRACE("{}: proc: {}, real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func)
return func;

@ -6,6 +6,7 @@
#include <algorithm>
#include <atomic>
#include <cstring>
#include <spdlog/spdlog.h>
#include "real_dlsym.h"
#include "loaders/loader_glx.h"
#include "loaders/loader_x11.h"
@ -47,7 +48,7 @@ void* get_glx_proc_address(const char* name) {
func = get_proc_address( name );
if (!func) {
std::cerr << "MANGOHUD: Failed to get function '" << name << "'" << std::endl;
SPDLOG_ERROR("Failed to get function '{}'", name);
}
return func;
@ -59,9 +60,7 @@ EXPORT_C_(void *) glXCreateContext(void *dpy, void *vis, void *shareList, int di
void *ctx = glx.CreateContext(dpy, vis, shareList, direct);
if (ctx)
refcnt++;
#ifndef NDEBUG
std::cerr << __func__ << ":" << ctx << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, ctx);
return ctx;
}
@ -71,9 +70,7 @@ EXPORT_C_(void *) glXCreateContextAttribs(void *dpy, void *config,void *share_co
void *ctx = glx.CreateContextAttribs(dpy, config, share_context, direct, attrib_list);
if (ctx)
refcnt++;
#ifndef NDEBUG
std::cerr << __func__ << ":" << ctx << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, ctx);
return ctx;
}
@ -83,9 +80,7 @@ EXPORT_C_(void *) glXCreateContextAttribsARB(void *dpy, void *config,void *share
void *ctx = glx.CreateContextAttribsARB(dpy, config, share_context, direct, attrib_list);
if (ctx)
refcnt++;
#ifndef NDEBUG
std::cerr << __func__ << ":" << ctx << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, ctx);
return ctx;
}
@ -96,25 +91,18 @@ EXPORT_C_(void) glXDestroyContext(void *dpy, void *ctx)
refcnt--;
if (refcnt <= 0)
imgui_shutdown();
#ifndef NDEBUG
std::cerr << __func__ << ":" << ctx << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, ctx);
}
EXPORT_C_(int) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
glx.Load();
#ifndef NDEBUG
std::cerr << __func__ << ": " << drawable << ", " << ctx << std::endl;
#endif
SPDLOG_DEBUG("{}: {}, {}", __func__, drawable, ctx);
int ret = glx.MakeCurrent(dpy, drawable, ctx);
if (!is_blacklisted()) {
if (ret) {
imgui_set_context(ctx);
#ifndef NDEBUG
std::cerr << "MANGOHUD: GL ref count: " << refcnt << "\n";
#endif
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
@ -159,6 +147,7 @@ static void do_imgui_swap(void *dpy, void *drawable)
break;
}
SPDLOG_TRACE("swap buffers: {}x{}", width, height);
imgui_render(width, height);
}
}
@ -196,9 +185,7 @@ EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t targe
}
EXPORT_C_(void) glXSwapIntervalEXT(void *dpy, void *draw, int interval) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, interval);
glx.Load();
if (!glx.SwapIntervalEXT)
return;
@ -210,9 +197,7 @@ EXPORT_C_(void) glXSwapIntervalEXT(void *dpy, void *draw, int interval) {
}
EXPORT_C_(int) glXSwapIntervalSGI(int interval) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, interval);
glx.Load();
if (!glx.SwapIntervalSGI)
return -1;
@ -224,9 +209,7 @@ EXPORT_C_(int) glXSwapIntervalSGI(int interval) {
}
EXPORT_C_(int) glXSwapIntervalMESA(unsigned int interval) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, interval);
glx.Load();
if (!glx.SwapIntervalMESA)
return -1;
@ -256,9 +239,7 @@ EXPORT_C_(int) glXGetSwapIntervalMESA() {
}
}
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
SPDLOG_DEBUG("{}: {}", __func__, interval);
return interval;
}
@ -300,10 +281,10 @@ EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name)
}
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
//std::cerr << __func__ << ":" << procName << std::endl;
void *real_func = get_glx_proc_address((const char*)procName);
void *func = mangohud_find_glx_ptr( (const char*)procName );
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func)
return func;
@ -311,10 +292,9 @@ EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
}
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) {
//std::cerr << __func__ << ":" << procName << std::endl;
void *real_func = get_glx_proc_address((const char*)procName);
void *func = mangohud_find_glx_ptr( (const char*)procName );
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func)
return func;

@ -1,12 +1,31 @@
#include "gpu.h"
#include <inttypes.h>
#include <memory>
#include <functional>
#include <thread>
#include <cstring>
#include <spdlog/spdlog.h>
#include "nvctrl.h"
#include "timing.hpp"
#ifdef HAVE_NVML
#include "nvidia_info.h"
#endif
struct gpuInfo gpu_info;
#ifdef HAVE_LIBDRM_AMDGPU
//#include "auth.h"
#include <xf86drm.h>
#include <libdrm/amdgpu_drm.h>
#include <libdrm/amdgpu.h>
#include <unistd.h>
#include <fcntl.h>
#include "loaders/loader_libdrm.h"
#endif
using namespace std::chrono_literals;
struct gpuInfo gpu_info {};
amdgpu_files amdgpu {};
decltype(&getAmdGpuInfo) getAmdGpuInfo_actual = nullptr;
bool checkNvidia(const char *pci_dev){
bool nvSuccess = false;
@ -120,3 +139,176 @@ void getAmdGpuInfo(){
gpu_info.powerUsage = value / 1000000;
}
}
#ifdef HAVE_LIBDRM_AMDGPU
#define DRM_ATLEAST_VERSION(ver, maj, min) \
(ver->version_major > maj || (ver->version_major == maj && ver->version_minor >= min))
enum {
GRBM_STATUS = 0x8010,
};
static std::unique_ptr<libdrm_amdgpu_loader> libdrm_amdgpu_ptr;
static int getgrbm_amdgpu(amdgpu_device_handle dev, uint32_t *out) {
return libdrm_amdgpu_ptr->amdgpu_read_mm_registers(dev, GRBM_STATUS / 4, 1,
0xffffffff, 0, out);
}
struct amdgpu_handles
{
amdgpu_device_handle dev;
int fd;
uint32_t version_major, version_minor, gui_percent {0};
uint32_t ticks = 60, ticks_per_sec = 120;
std::chrono::nanoseconds sleep_interval {};
bool quit = false;
std::thread collector;
amdgpu_handles(amdgpu_device_handle dev_, int fd_, uint32_t major, uint32_t minor)
: dev(dev_)
, fd(fd_)
, version_major(major)
, version_minor(minor)
{
set_sampling_period(500000000 /* 500ms */);
collector = std::thread(&amdgpu_handles::amdgpu_poll, this);
}
~amdgpu_handles()
{
quit = true;
if (collector.joinable())
collector.join();
libdrm_amdgpu_ptr->amdgpu_device_deinitialize(dev);
close(fd);
}
void set_sampling_period(uint32_t period)
{
if (period < 10000000)
period = 10000000; /* 10ms */
ticks = ticks_per_sec * std::chrono::nanoseconds(period) / 1s;
sleep_interval = std::chrono::nanoseconds(period) / ticks;
SPDLOG_DEBUG("ticks: {}, {}ns", ticks, sleep_interval.count());
}
void amdgpu_poll()
{
uint32_t stat = 0, gui = 0, curr = 0;
while (!quit)
{
getgrbm_amdgpu(dev, &stat);
if (stat & (1U << 31)) // gui
gui++;
std::this_thread::sleep_for(sleep_interval);
curr++;
curr %= ticks;
if (!curr)
{
gui_percent = gui * 100 / ticks;
gui = 0;
}
}
}
};
typedef std::unique_ptr<amdgpu_handles> amdgpu_ptr;
static amdgpu_ptr amdgpu_dev;
void amdgpu_set_sampling_period(uint32_t period)
{
if (amdgpu_dev)
amdgpu_dev->set_sampling_period(period);
}
bool amdgpu_open(const char *path) {
if (!g_libdrm.IsLoaded())
return false;
if (!libdrm_amdgpu_ptr)
libdrm_amdgpu_ptr = std::make_unique<libdrm_amdgpu_loader>();
if (!libdrm_amdgpu_ptr->IsLoaded())
return false;
int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
SPDLOG_ERROR("Failed to open DRM device: {}", strerror(errno));
return false;
}
drmVersionPtr ver = g_libdrm.drmGetVersion(fd);
if (!ver) {
SPDLOG_ERROR("Failed to query driver version: {}", strerror(errno));
close(fd);
return false;
}
if (strcmp(ver->name, "amdgpu") || !DRM_ATLEAST_VERSION(ver, 3, 11)) {
SPDLOG_ERROR("Unsupported driver/version: {} {}.{}.{}", ver->name, ver->version_major, ver->version_minor, ver->version_patchlevel);
close(fd);
g_libdrm.drmFreeVersion(ver);
return false;
}
g_libdrm.drmFreeVersion(ver);
/*
if (!authenticate_drm(fd)) {
close(fd);
return false;
}
*/
uint32_t drm_major, drm_minor;
amdgpu_device_handle dev;
if (libdrm_amdgpu_ptr->amdgpu_device_initialize(fd, &drm_major, &drm_minor, &dev)){
SPDLOG_ERROR("Failed to initialize amdgpu device: {}", strerror(errno));
close(fd);
return false;
}
amdgpu_dev = std::make_unique<amdgpu_handles>(dev, fd, drm_major, drm_minor);
return true;
}
void getAmdGpuInfo_libdrm()
{
uint64_t value = 0;
uint32_t value32 = 0;
if (!amdgpu_dev || !DRM_ATLEAST_VERSION(amdgpu_dev, 3, 11))
{
getAmdGpuInfo();
getAmdGpuInfo_actual = getAmdGpuInfo;
return;
}
if (!libdrm_amdgpu_ptr->amdgpu_query_info(amdgpu_dev->dev, AMDGPU_INFO_VRAM_USAGE, sizeof(uint64_t), &value))
gpu_info.memoryUsed = float(value) / (1024 * 1024 * 1024);
// FIXME probably not correct sensor
if (!libdrm_amdgpu_ptr->amdgpu_query_info(amdgpu_dev->dev, AMDGPU_INFO_MEMORY, sizeof(uint64_t), &value))
gpu_info.memoryTotal = float(value) / (1024 * 1024 * 1024);
if (!libdrm_amdgpu_ptr->amdgpu_query_sensor_info(amdgpu_dev->dev, AMDGPU_INFO_SENSOR_GFX_SCLK, sizeof(uint32_t), &value32))
gpu_info.CoreClock = value32;
if (!libdrm_amdgpu_ptr->amdgpu_query_sensor_info(amdgpu_dev->dev, AMDGPU_INFO_SENSOR_GFX_MCLK, sizeof(uint32_t), &value32)) // XXX Doesn't work on APUs
gpu_info.MemClock = value32;
//if (!libdrm_amdgpu_ptr->amdgpu_query_sensor_info(amdgpu_dev->dev, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(uint32_t), &value32))
// gpu_info.load = value32;
gpu_info.load = amdgpu_dev->gui_percent;
if (!libdrm_amdgpu_ptr->amdgpu_query_sensor_info(amdgpu_dev->dev, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(uint32_t), &value32))
gpu_info.temp = value32 / 1000;
if (!libdrm_amdgpu_ptr->amdgpu_query_sensor_info(amdgpu_dev->dev, AMDGPU_INFO_SENSOR_GPU_AVG_POWER, sizeof(uint32_t), &value32))
gpu_info.powerUsage = value32;
}
#endif

@ -2,7 +2,8 @@
#ifndef MANGOHUD_GPU_H
#define MANGOHUD_GPU_H
#include <stdio.h>
#include <cstdio>
#include <cstdint>
struct amdgpu_files
{
@ -31,6 +32,12 @@ extern struct gpuInfo gpu_info;
void getNvidiaGpuInfo(void);
void getAmdGpuInfo(void);
#ifdef HAVE_LIBDRM_AMDGPU
void getAmdGpuInfo_libdrm();
bool amdgpu_open(const char *path);
void amdgpu_set_sampling_period(uint32_t period);
#endif
extern decltype(&getAmdGpuInfo) getAmdGpuInfo_actual;
bool checkNvidia(const char *pci_dev);
extern void nvapi_util();
extern bool checkNVAPI();

@ -1,12 +1,22 @@
#include <spdlog/spdlog.h>
#include <algorithm>
#include <functional>
#include <sstream>
#include <cmath>
#include "overlay.h"
#include "overlay_params.h"
#include "hud_elements.h"
#include "logging.h"
#include "battery.h"
#include "cpu.h"
#include "memory.h"
#include "mesa/util/macros.h"
#include "string_utils.h"
#include <IconsForkAwesome.h>
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
// Cut from https://github.com/ocornut/imgui/pull/2943
// Probably move to ImGui
float SRGBToLinear(float in)
@ -45,6 +55,20 @@ ImVec4 LinearToSRGB(ImVec4 col)
return col;
}
template<typename T, typename R = float>
R format_units(T value, const char*& unit)
{
static const char* const units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"};
size_t u = 0;
R out_value = value;
while (out_value > 1023 && u < ARRAY_SIZE(units)) {
out_value /= 1024;
++u;
}
unit = units[u];
return out_value;
}
void HudElements::convert_colors(struct overlay_params& params)
{
HUDElements.colors.update = false;
@ -270,6 +294,7 @@ void HudElements::core_load(){
}
}
}
void HudElements::io_stats(){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] || HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]){
ImGui::TableNextRow(); ImGui::TableNextColumn();
@ -321,6 +346,7 @@ void HudElements::vram(){
}
}
}
void HudElements::ram(){
#ifdef __gnu_linux__
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram]){
@ -332,7 +358,7 @@ void HudElements::ram(){
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::Text("GiB");
ImGui::PopFont();
}
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram] && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_swap]){
ImGui::TableNextColumn();
@ -345,6 +371,47 @@ void HudElements::ram(){
#endif
}
void HudElements::procmem()
{
#ifdef __gnu_linux__
const char* unit = nullptr;
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem])
return;
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::TextColored(HUDElements.colors.ram, "PMEM");
ImGui::TableNextColumn();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", format_units(proc_mem.resident, unit));
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::Text("%s", unit);
ImGui::PopFont();
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_shared]){
ImGui::TableNextColumn();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", format_units(proc_mem.shared, unit));
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::Text("%s", unit);
ImGui::PopFont();
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_shared] && HUDElements.params->table_columns < 4){
ImGui::TableNextRow();
ImGui::TableNextColumn();
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_virt]){
ImGui::TableNextColumn();
right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", format_units(proc_mem.virt, unit));
ImGui::SameLine(0,1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::Text("%s", unit);
ImGui::PopFont();
}
#endif
}
void HudElements::fps(){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps]){
ImGui::TableNextRow(); ImGui::TableNextColumn();
@ -398,7 +465,7 @@ void HudElements::engine_version(){
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::PushFont(HUDElements.sw_stats->font1);
if (HUDElements.is_vulkan) {
if ((HUDElements.sw_stats->engineName == "DXVK" || HUDElements.sw_stats->engineName == "VKD3D")){
if ((HUDElements.sw_stats->engine == EngineTypes::DXVK || HUDElements.sw_stats->engine == EngineTypes::VKD3D)){
ImGui::TextColored(HUDElements.colors.engine,
"%s/%d.%d.%d", HUDElements.sw_stats->engineVersion.c_str(),
HUDElements.sw_stats->version_vk.major,
@ -487,6 +554,9 @@ void HudElements::frame_timing(){
void HudElements::media_player(){
#ifdef HAVE_DBUS
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_media_player])
return;
ImGui::TableNextRow(); ImGui::TableNextColumn();
uint32_t f_idx = (HUDElements.sw_stats->n_frames - 1) % ARRAY_SIZE(HUDElements.sw_stats->frames_stats);
uint64_t frame_timing = HUDElements.sw_stats->frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing];
@ -495,7 +565,7 @@ void HudElements::media_player(){
ImGui::PushFont(&scaled_font);
{
std::lock_guard<std::mutex> lck(main_metadata.mtx);
render_mpris_metadata(*HUDElements.params, main_metadata, frame_timing, true);
render_mpris_metadata(*HUDElements.params, main_metadata, frame_timing);
}
ImGui::PopFont();
#endif
@ -534,7 +604,7 @@ void HudElements::show_fps_limit(){
void HudElements::custom_text_center(){
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::PushFont(HUDElements.sw_stats->font1);
std::string value = HUDElements.ordered_functions[HUDElements.place].second;
const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
center_text(value);
ImGui::TextColored(HUDElements.colors.text, "%s",value.c_str());
ImGui::NewLine();
@ -544,13 +614,13 @@ void HudElements::custom_text_center(){
void HudElements::custom_text(){
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::PushFont(HUDElements.sw_stats->font1);
std::string value = HUDElements.ordered_functions[HUDElements.place].second;
const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
ImGui::TextColored(HUDElements.colors.text, "%s",value.c_str());
ImGui::PopFont();
}
void HudElements::_exec(){
std::string value = HUDElements.ordered_functions[HUDElements.place].second;
//const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::TableNextColumn();
for (auto& item : HUDElements.exec_list){
@ -583,6 +653,7 @@ void HudElements::vkbasalt(){
}
void HudElements::battery(){
#ifdef __gnu_linux__
if (Battery_Stats.batt_count > 0) {
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery]) {
ImGui::TableNextRow(); ImGui::TableNextColumn();
@ -619,13 +690,14 @@ void HudElements::battery(){
}
}
}
#endif
}
void HudElements::graphs(){
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Dummy(ImVec2(0.0f, real_font_size.y));
std::string value = HUDElements.ordered_functions[HUDElements.place].second;
const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
std::vector<float> arr(50, 0);
ImGui::PushFont(HUDElements.sw_stats->font1);
@ -742,9 +814,9 @@ void HudElements::graphs(){
ImGui::PopStyleColor(1);
}
void HudElements::sort_elements(std::pair<std::string, std::string> option){
auto param = option.first;
auto value = option.second;
void HudElements::sort_elements(const std::pair<std::string, std::string>& option){
const auto& param = option.first;
const auto& value = option.second;
// Use this to always add to front of vector
//ordered_functions.insert(ordered_functions.begin(),std::make_pair(param,value));
@ -757,6 +829,7 @@ void HudElements::sort_elements(std::pair<std::string, std::string> option){
if (param == "io_stats") { ordered_functions.push_back({io_stats, value}); }
if (param == "vram") { ordered_functions.push_back({vram, value}); }
if (param == "ram") { ordered_functions.push_back({ram, value}); }
if (param == "procmem") { ordered_functions.push_back({procmem, value}); }
if (param == "fps") { ordered_functions.push_back({fps, value}); }
if (param == "engine_version") { ordered_functions.push_back({engine_version, value}); }
if (param == "gpu_name") { ordered_functions.push_back({gpu_name, value}); }
@ -782,7 +855,9 @@ void HudElements::sort_elements(std::pair<std::string, std::string> option){
if (find(permitted_params.begin(), permitted_params.end(), value) != permitted_params.end())
ordered_functions.push_back({graphs, value});
else
printf("MANGOHUD: Unrecognized graph type: %s\n", value.c_str());
{
spdlog::error("Unrecognized graph type: {}", value);
}
}
}
return;

@ -1,17 +1,16 @@
#pragma once
#include "overlay.h"
#include "overlay_params.h"
#include <functional>
#include <map>
#include <sstream>
#include <logging.h>
#include <battery.h>
#include <vector>
#include <string>
#include <utility>
#include <imgui.h>
#include "timing.hpp"
struct overlay_params;
class HudElements{
public:
struct swapchain_stats *sw_stats;
struct overlay_params *params;
struct exec_list {
struct exec_entry {
int pos;
std::string value;
std::string ret;
@ -25,12 +24,12 @@ class HudElements{
std::vector<std::pair<std::string, std::string>> options;
std::vector<std::pair<void(*)(), std::string >> ordered_functions;
int min, max, gpu_core_max, gpu_mem_max, cpu_temp_max, gpu_temp_max;
std::vector<std::string> permitted_params = {
const std::vector<std::string> permitted_params = {
"gpu_load", "cpu_load", "gpu_core_clock", "gpu_mem_clock",
"vram", "ram", "cpu_temp", "gpu_temp"
};
std::vector<exec_list> exec_list;
void sort_elements(std::pair<std::string, std::string> option);
std::vector<exec_entry> exec_list;
void sort_elements(const std::pair<std::string, std::string>& option);
void legacy_elements();
void update_exec();
static void version();
@ -41,6 +40,7 @@ class HudElements{
static void io_stats();
static void vram();
static void ram();
static void procmem();
static void fps();
static void engine_version();
static void gpu_name();

@ -13,7 +13,12 @@ void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& par
auto elapsedReloadCfg = now - reload_cfg_press;
auto elapsedUpload = now - last_upload_press;
auto keyPressDelay = 500ms;
static Clock::time_point last_check;
if (now - last_check < 100ms)
return;
last_check = now;
auto keyPressDelay = 400ms;
if (elapsedF2 >= keyPressDelay){
#if defined(HAVE_X11) || defined(_WIN32)
@ -80,6 +85,7 @@ void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& par
#endif
if (pressed){
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
_params = params;
reload_cfg_press = now;
}
}

@ -1,6 +1,7 @@
#include "loaders/loader_dbus.h"
#include <iostream>
#include <spdlog/spdlog.h>
// Put these sanity checks here so that they fire at most once
// (to avoid cluttering the build output).
@ -26,7 +27,7 @@ bool libdbus_loader::Load(const std::string& library_name) {
#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)
library_ = dlopen(library_name.c_str(), RTLD_LAZY);
if (!library_) {
std::cerr << "MANGOHUD: Failed to open " << "" MANGOHUD_ARCH << " " << library_name << ": " << dlerror() << std::endl;
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror());
return false;
}

@ -1,4 +1,5 @@
#include <iostream>
#include <spdlog/spdlog.h>
#include "real_dlsym.h"
#include "loaders/loader_glx.h"
@ -24,7 +25,7 @@ bool glx_loader::Load() {
if (!handle)
handle = real_dlopen("libGL.so.1", RTLD_LAZY);
if (!handle) {
std::cerr << "MANGOHUD: Failed to open " << "" MANGOHUD_ARCH << " libGL.so.1: " << dlerror() << std::endl;
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libGL.so.1: {}", dlerror());
return false;
}

@ -0,0 +1,177 @@
#include "loaders/loader_libdrm.h"
#include <iostream>
#include <spdlog/spdlog.h>
// Put these sanity checks here so that they fire at most once
// (to avoid cluttering the build output).
#if !defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN) && !defined(LIBRARY_LOADER_LIBDRM_H_DT_NEEDED)
#error neither LIBRARY_LOADER_LIBDRM_H_DLOPEN nor LIBRARY_LOADER_LIBDRM_H_DT_NEEDED defined
#endif
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN) && defined(LIBRARY_LOADER_LIBDRM_H_DT_NEEDED)
#error both LIBRARY_LOADER_LIBDRM_H_DLOPEN and LIBRARY_LOADER_LIBDRM_H_DT_NEEDED defined
#endif
libdrm_loader::libdrm_loader() : loaded_(false) {
Load();
}
libdrm_loader::~libdrm_loader() {
CleanUp(loaded_);
}
bool libdrm_loader::Load() {
if (loaded_) {
return true;
}
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN)
library = dlopen("libdrm.so.2", RTLD_LAZY);
if (!library) {
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libdrm.so.2: {}", dlerror());
return false;
}
drmGetVersion =
reinterpret_cast<decltype(this->drmGetVersion)>(
dlsym(library, "drmGetVersion"));
if (!drmGetVersion) {
CleanUp(true);
return false;
}
drmFreeVersion =
reinterpret_cast<decltype(this->drmFreeVersion)>(
dlsym(library, "drmFreeVersion"));
if (!drmFreeVersion) {
CleanUp(true);
return false;
}
drmCommandWriteRead =
reinterpret_cast<decltype(this->drmCommandWriteRead)>(
dlsym(library, "drmCommandWriteRead"));
if (!drmCommandWriteRead) {
CleanUp(true);
return false;
}
#endif
#if defined(LIBRARY_LOADER_LIBDRM_H_DT_NEEDED)
drmGetVersion = &::drmGetVersion;
drmFreeVersion = &::drmFreeVersion;
drmCommandWriteRead = &::drmCommandWriteRead;
#endif
loaded_ = true;
return true;
}
void libdrm_loader::CleanUp(bool unload) {
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN)
if (unload) {
dlclose(library);
library = nullptr;
}
#endif
loaded_ = false;
drmGetVersion = nullptr;
drmFreeVersion = nullptr;
drmCommandWriteRead = nullptr;
}
libdrm_amdgpu_loader::libdrm_amdgpu_loader() : loaded_(false) {
Load();
}
libdrm_amdgpu_loader::~libdrm_amdgpu_loader() {
CleanUp(loaded_);
}
bool libdrm_amdgpu_loader::Load() {
if (loaded_) {
return true;
}
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN)
library = dlopen("libdrm_amdgpu.so.1", RTLD_LAZY);
if (!library) {
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libdrm_amdgpu.so.1: {}", dlerror());
CleanUp(true);
return false;
}
amdgpu_device_initialize =
reinterpret_cast<decltype(this->amdgpu_device_initialize)>(
dlsym(library, "amdgpu_device_initialize"));
if (!amdgpu_device_initialize) {
CleanUp(true);
return false;
}
amdgpu_device_deinitialize =
reinterpret_cast<decltype(this->amdgpu_device_deinitialize)>(
dlsym(library, "amdgpu_device_deinitialize"));
if (!amdgpu_device_deinitialize) {
CleanUp(true);
return false;
}
amdgpu_query_info =
reinterpret_cast<decltype(this->amdgpu_query_info)>(
dlsym(library, "amdgpu_query_info"));
if (!amdgpu_query_info) {
CleanUp(true);
return false;
}
amdgpu_query_sensor_info =
reinterpret_cast<decltype(this->amdgpu_query_sensor_info)>(
dlsym(library, "amdgpu_query_sensor_info"));
if (!amdgpu_query_sensor_info) {
CleanUp(true);
return false;
}
amdgpu_read_mm_registers =
reinterpret_cast<decltype(this->amdgpu_read_mm_registers)>(
dlsym(library, "amdgpu_read_mm_registers"));
if (!amdgpu_read_mm_registers) {
CleanUp(true);
return false;
}
#endif
#if defined(LIBRARY_LOADER_LIBDRM_H_DT_NEEDED)
amdgpu_device_initialize = &::amdgpu_device_initialize;
amdgpu_device_deinitialize = &::amdgpu_device_deinitialize;
amdgpu_query_info = &::amdgpu_query_info;
amdgpu_query_sensor_info = &::amdgpu_query_sensor_info;
amdgpu_read_mm_registers = &::amdgpu_read_mm_registers;
#endif
loaded_ = true;
return true;
}
void libdrm_amdgpu_loader::CleanUp(bool unload) {
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN)
if (unload) {
dlclose(library);
library = nullptr;
}
#endif
loaded_ = false;
amdgpu_device_initialize = nullptr;
amdgpu_device_deinitialize = nullptr;
amdgpu_query_info = nullptr;
amdgpu_query_sensor_info = nullptr;
amdgpu_read_mm_registers = nullptr;
}
libdrm_loader g_libdrm;

@ -0,0 +1,82 @@
#ifndef LIBRARY_LOADER_LIBDRM_H
#define LIBRARY_LOADER_LIBDRM_H
#define LIBRARY_LOADER_LIBDRM_H_DLOPEN
#include <dlfcn.h>
#include <xf86drm.h>
//#include <libdrm/amdgpu_drm.h>
//#include <libdrm/amdgpu.h>
typedef struct amdgpu_device *amdgpu_device_handle;
int amdgpu_device_initialize(int fd,
uint32_t *major_version,
uint32_t *minor_version,
amdgpu_device_handle *device_handle);
int amdgpu_device_deinitialize(amdgpu_device_handle device_handle);
int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id,
unsigned size, void *value);
int amdgpu_query_sensor_info(amdgpu_device_handle dev, unsigned sensor_type,
unsigned size, void *value);
int amdgpu_read_mm_registers(amdgpu_device_handle dev, unsigned dword_offset,
unsigned count, uint32_t instance, uint32_t flags,
uint32_t *values);
class libdrm_loader {
public:
libdrm_loader();
~libdrm_loader();
bool Load();
bool IsLoaded() { return loaded_; }
decltype(&::drmGetVersion) drmGetVersion;
decltype(&::drmFreeVersion) drmFreeVersion;
decltype(&::drmCommandWriteRead) drmCommandWriteRead;
private:
void CleanUp(bool unload);
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN)
void* library;
#endif
bool loaded_;
// Disallow copy constructor and assignment operator.
libdrm_loader(const libdrm_loader&);
void operator=(const libdrm_loader&);
};
class libdrm_amdgpu_loader {
public:
libdrm_amdgpu_loader();
~libdrm_amdgpu_loader();
bool Load();
bool IsLoaded() { return loaded_; }
decltype(&::amdgpu_device_initialize) amdgpu_device_initialize;
decltype(&::amdgpu_device_deinitialize) amdgpu_device_deinitialize;
decltype(&::amdgpu_query_info) amdgpu_query_info;
decltype(&::amdgpu_query_sensor_info) amdgpu_query_sensor_info;
decltype(&::amdgpu_read_mm_registers) amdgpu_read_mm_registers;
private:
void CleanUp(bool unload);
#if defined(LIBRARY_LOADER_LIBDRM_H_DLOPEN)
void* library;
#endif
bool loaded_;
// Disallow copy constructor and assignment operator.
libdrm_amdgpu_loader(const libdrm_amdgpu_loader&);
void operator=(const libdrm_amdgpu_loader&);
};
extern libdrm_loader g_libdrm;
#endif // LIBRARY_LOADER_LIBDRM_H

@ -1,6 +1,7 @@
#include "loader_nvctrl.h"
#include <iostream>
#include <memory>
#include <spdlog/spdlog.h>
// Put these sanity checks here so that they fire at most once
// (to avoid cluttering the build output).
@ -35,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_) {
std::cerr << "MANGOHUD: Failed to open " << "" MANGOHUD_ARCH << " " << library_name << ": " << dlerror() << std::endl;
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror());
return false;
}

@ -4,6 +4,7 @@
#include "loader_nvml.h"
#include <iostream>
#include <memory>
#include <spdlog/spdlog.h>
// Put these sanity checks here so that they fire at most once
// (to avoid cluttering the build output).
@ -38,7 +39,7 @@ bool libnvml_loader::Load(const std::string& library_name) {
#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)
library_ = dlopen(library_name.c_str(), RTLD_LAZY);
if (!library_) {
std::cerr << "MANGOHUD: Failed to open " << "" MANGOHUD_ARCH << " " << library_name << ": " << dlerror() << std::endl;
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror());
return false;
}
#endif

@ -1,5 +1,6 @@
#include "loader_x11.h"
#include <iostream>
#include <spdlog/spdlog.h>
libx11_loader::libx11_loader() : loaded_(false) {
}
@ -15,7 +16,7 @@ bool libx11_loader::Load(const std::string& library_name) {
library_ = dlopen(library_name.c_str(), RTLD_LAZY);
if (!library_) {
std::cerr << "MANGOHUD: Failed to open " << "" MANGOHUD_ARCH << " " << library_name << ": " << dlerror() << std::endl;
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror());
return false;
}

@ -1,9 +1,11 @@
#include <sstream>
#include <iomanip>
#include <spdlog/spdlog.h>
#include "logging.h"
#include "overlay.h"
#include "config.h"
#include "file_utils.h"
#include "string_utils.h"
string os, cpu, gpu, ram, kernel, driver, cpusched;
bool sysInfoFetched = false;
@ -58,9 +60,7 @@ void upload_files(const std::vector<std::string>& logFiles){
void writeFile(string filename){
auto& logArray = logger->get_log_data();
#ifndef NDEBUG
std::cerr << "Writing log file [" << filename << "], " << logArray.size() << " entries\n";
#endif
SPDLOG_DEBUG("Writing log file [{}], {} entries", filename, logArray.size());
std::ofstream out(filename, ios::out | ios::app);
if (out){
out << "os," << "cpu," << "gpu," << "ram," << "kernel," << "driver," << "cpuscheduler" << endl;
@ -96,12 +96,11 @@ string get_log_suffix(){
return log_name;
}
void logging(void *params_void){
overlay_params *params = reinterpret_cast<overlay_params *>(params_void);
void logging(){
logger->wait_until_data_valid();
while (logger->is_active()){
logger->try_log();
this_thread::sleep_for(chrono::milliseconds(params->log_interval));
this_thread::sleep_for(chrono::milliseconds(_params.log_interval));
}
}
@ -110,9 +109,7 @@ Logger::Logger(overlay_params* in_params)
m_values_valid(false),
m_params(in_params)
{
#ifndef NDEBUG
std::cerr << "Logger constructed!\n";
#endif
SPDLOG_DEBUG("Logger constructed!");
}
void Logger::start_logging() {
@ -120,8 +117,8 @@ void Logger::start_logging() {
m_values_valid = false;
m_logging_on = true;
m_log_start = Clock::now();
if((!m_params->output_folder.empty()) && (m_params->log_interval != 0)){
std::thread(logging, m_params).detach();
if((!_params.output_folder.empty()) && (_params.log_interval != 0)){
std::thread(logging).detach();
}
}
@ -130,13 +127,13 @@ void Logger::stop_logging() {
m_logging_on = false;
m_log_end = Clock::now();
std::thread(calculate_benchmark_data, m_params).detach();
calculate_benchmark_data();
if(!m_params->output_folder.empty()) {
if(!_params.output_folder.empty()) {
std::string program = get_wine_exe_name();
if (program.empty())
program = get_program_name();
m_log_files.emplace_back(m_params->output_folder + "/" + program + "_" + get_log_suffix());
m_log_files.emplace_back(_params.output_folder + "/" + program + "_" + get_log_suffix());
std::thread(writeFile, m_log_files.back()).detach();
}
}
@ -152,7 +149,7 @@ void Logger::try_log() {
currentLogData.frametime = frametime;
m_log_array.push_back(currentLogData);
if(m_params->log_duration && (elapsedLog >= std::chrono::seconds(m_params->log_duration))){
if(_params.log_duration && (elapsedLog >= std::chrono::seconds(_params.log_duration))){
stop_logging();
}
}

@ -1,12 +1,15 @@
#include <spdlog/spdlog.h>
#include "memory.h"
#include <iomanip>
#include <cstring>
#include <stdio.h>
#include <iostream>
#include <thread>
#include <unistd.h>
struct memory_information mem_info;
float memused, memmax, swapused, swapmax;
struct process_mem proc_mem {};
FILE *open_file(const char *file, int *reported) {
FILE *fp = nullptr;
@ -15,7 +18,7 @@ FILE *open_file(const char *file, int *reported) {
if (fp == nullptr) {
if ((reported == nullptr) || *reported == 0) {
// NORM_ERR("can't open %s: %s", file, strerror(errno));
SPDLOG_ERROR("can't open {}: {}", file, strerror(errno));
if (reported != nullptr) { *reported = 1; }
}
return nullptr;
@ -100,3 +103,29 @@ void update_meminfo(void) {
fclose(meminfo_fp);
}
void update_procmem()
{
static int reported = 0;
FILE *statm = open_file("/proc/self/statm", &reported);
if (!statm)
return;
static auto pageSize = sysconf(_SC_PAGESIZE);
if (pageSize < 0) pageSize = 4096;
long long int temp[7];
if (fscanf(statm, "%lld %lld %lld %lld %lld %lld %lld",
&temp[0], &temp[1], &temp[2], &temp[3],
&temp[4], /* unused since Linux 2.6; always 0 */
&temp[5], &temp[6]) == 7)
{
proc_mem.virt = temp[0] * pageSize;// / (1024.f * 1024.f); //MiB
proc_mem.resident = temp[1] * pageSize;// / (1024.f * 1024.f); //MiB
proc_mem.shared = temp[2] * pageSize;// / (1024.f * 1024.f); //MiB;
proc_mem.text = temp[3];
proc_mem.data = temp[5];
proc_mem.dirty = temp[6];
}
fclose(statm);
}

@ -15,7 +15,15 @@ struct memory_information {
unsigned long long bufmem, buffers, cached;
};
struct process_mem
{
int64_t virt, resident, shared;
int64_t text, data, dirty;
};
extern process_mem proc_mem;
void update_meminfo(void);
void update_procmem();
FILE *open_file(const char *file, int *reported);
#endif //MANGOHUD_MEMORY_H

@ -53,6 +53,7 @@ vklayer_files = files(
'gpu.cpp',
'vulkan.cpp',
'blacklist.cpp',
'file_utils.cpp',
)
opengl_files = []
if ['windows', 'mingw'].contains(host_machine.system())
@ -72,7 +73,6 @@ endif
if is_unixy
vklayer_files += files(
'cpu.cpp',
'file_utils.cpp',
'memory.cpp',
'iostats.cpp',
'notify.cpp',
@ -149,6 +149,16 @@ if is_unixy
'loaders/loader_dbus.cpp',
)
endif
# if get_option('with_libdrm_amdgpu').enabled() and dep_libdrm.found() and dep_libdrm_amdgpu.found()
if get_option('with_libdrm_amdgpu').enabled() and dep_libdrm.found()
pre_args += '-DHAVE_LIBDRM_AMDGPU'
#if dep_xcb.found() and dep_xcb_dri2.found()
vklayer_files += files(
'loaders/loader_libdrm.cpp',
)
#endif
endif
endif
link_args = cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro', '-Wl,--exclude-libs,ALL'])
@ -176,6 +186,9 @@ vklayer_mesa_overlay = shared_library(
dependencies : [
vulkan_wsi_deps,
dearimgui_dep,
spdlog_dep,
dep_libdrm,
#dep_libdrm_amdgpu,
dbus_dep,
dep_dl,
dep_rt,

@ -3,6 +3,7 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <spdlog/spdlog.h>
#include "config.h"
#include "notify.h"
@ -27,9 +28,7 @@ static void fileChanged(void *params_void) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
parse_overlay_config(&local_params, getenv("MANGOHUD_CONFIG"));
if ((event->mask & IN_DELETE_SELF) || (nt->params->config_file_path != local_params.config_file_path)) {
#ifndef NDEBUG
fprintf(stderr, "MANGOHUD: watching config file: %s\n", local_params.config_file_path.c_str());
#endif
SPDLOG_DEBUG("Watching config file: {}", local_params.config_file_path.c_str());
inotify_rm_watch(nt->fd, nt->wd);
nt->wd = inotify_add_watch(nt->fd, local_params.config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF);
}
@ -46,7 +45,7 @@ bool start_notifier(notify_thread& nt)
{
nt.fd = inotify_init1(IN_NONBLOCK);
if (nt.fd < 0) {
perror("MANGOHUD: inotify_init1");
SPDLOG_ERROR("inotify_init1 failed: {}", strerror(errno));
return false;
}

@ -4,6 +4,7 @@
#include <unordered_map>
#include <memory>
#include <functional>
#include <spdlog/spdlog.h>
#include "nvctrl.h"
#include "loaders/loader_nvctrl.h"
#include "loaders/loader_x11.h"
@ -25,7 +26,7 @@ static bool find_nv_x11(libnvctrl_loader& nvctrl, Display*& dpy)
if (d) {
if (nvctrl.XNVCTRLIsNvScreen(d, 0)) {
dpy = d;
std::cerr << "MANGOHUD: XNVCtrl is using display " << buf << std::endl;
SPDLOG_DEBUG("XNVCtrl is using display {}", buf);
return true;
}
g_x11->XCloseDisplay(d);
@ -36,14 +37,12 @@ static bool find_nv_x11(libnvctrl_loader& nvctrl, Display*& dpy)
bool checkXNVCtrl()
{
if (!g_x11->IsLoaded()) {
std::cerr << "MANGOHUD: XNVCtrl: X11 loader failed to load\n";
if (!g_x11->IsLoaded())
return false;
}
auto& nvctrl = get_libnvctrl_loader();
if (!nvctrl.IsLoaded()) {
std::cerr << "MANGOHUD: XNVCtrl loader failed to load\n";
SPDLOG_ERROR("XNVCtrl loader failed to load");
return false;
}
@ -51,7 +50,7 @@ bool checkXNVCtrl()
nvctrlSuccess = find_nv_x11(nvctrl, dpy);
if (!nvctrlSuccess) {
std::cerr << "MANGOHUD: XNVCtrl didn't find the correct display" << std::endl;
SPDLOG_ERROR("XNVCtrl didn't find the correct display");
return false;
}
@ -86,7 +85,6 @@ static void parse_token(std::string token, string_map& options) {
param = token.substr(0, equal);
trim(param);
trim(value);
//std::cerr << __func__ << ": " << param << "=" << value << std::endl;
if (!param.empty())
options[param] = value;
}
@ -94,7 +92,7 @@ static void parse_token(std::string token, string_map& options) {
char* get_attr_target_string(libnvctrl_loader& nvctrl, int attr, int target_type, int target_id) {
char* c = nullptr;
if (!nvctrl.XNVCTRLQueryTargetStringAttribute(display.get(), target_type, target_id, 0, attr, &c)) {
std::cerr << "Failed to query attribute '" << attr << "'.\n";
SPDLOG_ERROR("Failed to query attribute '{}'", attr);
}
return c;
}

@ -1,3 +1,4 @@
#include <spdlog/spdlog.h>
#include "loaders/loader_nvml.h"
#include "nvidia_info.h"
#include <iostream>
@ -16,30 +17,30 @@ bool checkNVML(const char* pciBusId){
if (nvml.IsLoaded()){
result = nvml.nvmlInit();
if (NVML_SUCCESS != result) {
std::cerr << "MANGOHUD: Nvidia module not loaded\n";
SPDLOG_ERROR("Nvidia module not loaded");
} else {
nvmlReturn_t ret = NVML_ERROR_UNKNOWN;
if (pciBusId && ((ret = nvml.nvmlDeviceGetHandleByPciBusId(pciBusId, &nvidiaDevice)) != NVML_SUCCESS)) {
std::cerr << "MANGOHUD: Getting device handle by PCI bus ID failed: " << nvml.nvmlErrorString(ret) << "\n";
std::cerr << " Using index 0.\n";
SPDLOG_ERROR("Getting device handle by PCI bus ID failed: {}", nvml.nvmlErrorString(ret));
SPDLOG_ERROR("Using index 0.");
}
if (ret != NVML_SUCCESS)
ret = nvml.nvmlDeviceGetHandleByIndex(0, &nvidiaDevice);
if (ret != NVML_SUCCESS)
std::cerr << "MANGOHUD: Getting device handle failed: " << nvml.nvmlErrorString(ret) << "\n";
SPDLOG_ERROR("Getting device handle failed: {}", nvml.nvmlErrorString(ret));
nvmlSuccess = (ret == NVML_SUCCESS);
if (ret == NVML_SUCCESS)
nvml.nvmlDeviceGetPciInfo_v3(nvidiaDevice, &nvidiaPciInfo);
return nvmlSuccess;
}
} else {
std::cerr << "MANGOHUD: Failed to load NVML\n";
SPDLOG_ERROR("Failed to load NVML");
}
return false;
}

@ -1,6 +1,9 @@
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <thread>
#include <condition_variable>
#include <spdlog/spdlog.h>
#include "overlay.h"
#include "logging.h"
#include "cpu.h"
@ -10,10 +13,26 @@
#include "mesa/util/macros.h"
#include "string_utils.h"
#include "battery.h"
#include "string_utils.h"
#include "file_utils.h"
#include "gpu.h"
#include "logging.h"
#include "cpu.h"
#include "memory.h"
#include "pci_ids.h"
#include "timing.hpp"
#ifdef __gnu_linux__
#include <libgen.h>
#include <unistd.h>
#endif
#ifdef HAVE_DBUS
float g_overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */;
#endif
string gpuString,wineVersion,wineProcess;
int32_t deviceID;
bool gui_open = false;
struct benchmark_stats benchmark;
struct fps_limit fps_limit_stats {};
@ -23,9 +42,11 @@ const char* engines[] = {"Unknown", "OpenGL", "VULKAN", "DXVK", "VKD3D", "DAMAVA
void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID)
{
if (params.enabled[OVERLAY_PARAM_ENABLED_battery]) {
Battery_Stats.update();
}
#ifdef __gnu_linux__
if (params.enabled[OVERLAY_PARAM_ENABLED_battery]) {
Battery_Stats.update();
}
#endif
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_stats] || logger->is_active()) {
cpuStats.UpdateCPUData();
#ifdef __gnu_linux__
@ -39,8 +60,8 @@ void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& par
#endif
}
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] || logger->is_active()) {
if (vendorID == 0x1002)
getAmdGpuInfo();
if (vendorID == 0x1002 && getAmdGpuInfo_actual)
getAmdGpuInfo_actual();
if (vendorID == 0x10de)
getNvidiaGpuInfo();
@ -51,6 +72,8 @@ void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& par
#ifdef __gnu_linux__
if (params.enabled[OVERLAY_PARAM_ENABLED_ram] || params.enabled[OVERLAY_PARAM_ENABLED_swap] || logger->is_active())
update_meminfo();
if (params.enabled[OVERLAY_PARAM_ENABLED_procmem])
update_procmem();
if (params.enabled[OVERLAY_PARAM_ENABLED_io_read] || params.enabled[OVERLAY_PARAM_ENABLED_io_write])
getIoStats(&sw_stats.io);
#endif
@ -75,6 +98,54 @@ void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& par
HUDElements.update_exec();
}
struct hw_info_updater
{
bool quit = false;
std::thread thread {};
struct swapchain_stats sw_stats;
struct overlay_params params;
uint32_t vendorID;
bool update_hw_info_thread = false;
std::condition_variable cv_hwupdate;
std::mutex cv_m_hwupdate;
hw_info_updater(struct swapchain_stats& sw_stats_, struct overlay_params& params_, uint32_t vendorID_)
: sw_stats(sw_stats_)
, params(params_)
, vendorID(vendorID_)
{
thread = std::thread(&hw_info_updater::run, this);
}
~hw_info_updater()
{
quit = true;
cv_hwupdate.notify_all();
if (thread.joinable())
thread.join();
}
void update()
{
update_hw_info_thread = true;
cv_hwupdate.notify_all();
}
void run(){
while (!quit){
std::unique_lock<std::mutex> lk(cv_m_hwupdate);
cv_hwupdate.wait(lk, [&]{ return update_hw_info_thread || quit; });
if (quit) break;
update_hw_info(sw_stats, params, vendorID);
update_hw_info_thread = false;
}
}
};
static std::unique_ptr<hw_info_updater> hw_update_thread;
void update_hud_info(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID){
uint32_t f_idx = sw_stats.n_frames % ARRAY_SIZE(sw_stats.frames_stats);
uint64_t now = os_time_get_nano(); /* ns */
@ -90,7 +161,11 @@ void update_hud_info(struct swapchain_stats& sw_stats, struct overlay_params& pa
frametime = (now - sw_stats.last_present_time) / 1000;
if (elapsed >= params.fps_sampling_period) {
std::thread(update_hw_info, std::ref(sw_stats), std::ref(params), vendorID).detach();
if (!hw_update_thread)
hw_update_thread = std::make_unique<hw_info_updater>(sw_stats, params, vendorID);
else
hw_update_thread->update();
sw_stats.fps = fps;
if (params.enabled[OVERLAY_PARAM_ENABLED_time]) {
@ -114,9 +189,7 @@ void update_hud_info(struct swapchain_stats& sw_stats, struct overlay_params& pa
sw_stats.n_frames_since_update++;
}
void calculate_benchmark_data(void *params_void){
overlay_params *params = reinterpret_cast<overlay_params *>(params_void);
void calculate_benchmark_data(){
vector<float> sorted = benchmark.fps_data;
std::sort(sorted.begin(), sorted.end());
benchmark.percentile_data.clear();
@ -128,7 +201,7 @@ void calculate_benchmark_data(void *params_void){
size_t max_label_size = 0;
for (std::string percentile : params->benchmark_percentiles) {
for (std::string percentile : _params.benchmark_percentiles) {
float result;
// special case handling for a mean-based average
@ -229,7 +302,7 @@ void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...)
ImGui::TextColored(col,"%s",buffer);
}
void center_text(std::string& text)
void center_text(const std::string& text)
{
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(text.c_str()).x / 2));
}
@ -256,7 +329,7 @@ float get_ticker_limited_pos(float pos, float tw, float& left_limit, float& righ
}
#ifdef HAVE_DBUS
void render_mpris_metadata(struct overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing, bool is_main)
void render_mpris_metadata(struct overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing)
{
if (meta.meta.valid) {
auto color = ImGui::ColorConvertU32ToFloat4(params.media_player_color);
@ -265,13 +338,26 @@ void render_mpris_metadata(struct overlay_params& params, mutexed_metadata& meta
//ImGui::PushFont(data.font1);
if (meta.ticker.needs_recalc) {
meta.ticker.tw0 = ImGui::CalcTextSize(meta.meta.title.c_str()).x;
meta.ticker.tw1 = ImGui::CalcTextSize(meta.meta.artists.c_str()).x;
meta.ticker.tw2 = ImGui::CalcTextSize(meta.meta.album.c_str()).x;
meta.ticker.longest = std::max(std::max(
meta.ticker.tw0,
meta.ticker.tw1),
meta.ticker.tw2);
meta.ticker.formatted.clear();
meta.ticker.longest = 0;
for (const auto& f : params.media_player_format)
{
std::string str;
try
{
str = fmt::format(f,
fmt::arg("artist", meta.meta.artists),
fmt::arg("title", meta.meta.title),
fmt::arg("album", meta.meta.album));
}
catch (const fmt::v7::format_error& err)
{
SPDLOG_ERROR("formatting error in '{}': {}", f, err.what());
}
float w = ImGui::CalcTextSize(str.c_str()).x;
meta.ticker.longest = std::max(meta.ticker.longest, w);
meta.ticker.formatted.push_back({str, w});
}
meta.ticker.needs_recalc = false;
}
@ -288,34 +374,12 @@ void render_mpris_metadata(struct overlay_params& params, mutexed_metadata& meta
meta.ticker.pos -= .5f * (frame_timing / 16666666.7f /* ns */) * meta.ticker.dir;
for (auto order : params.media_player_order) {
switch (order) {
case MP_ORDER_TITLE:
{
new_pos = get_ticker_limited_pos(meta.ticker.pos, meta.ticker.tw0, left_limit, right_limit);
ImGui::SetCursorPosX(new_pos);
ImGui::TextColored(color, "%s", meta.meta.title.c_str());
}
break;
case MP_ORDER_ARTIST:
{
new_pos = get_ticker_limited_pos(meta.ticker.pos, meta.ticker.tw1, left_limit, right_limit);
ImGui::SetCursorPosX(new_pos);
ImGui::TextColored(color, "%s", meta.meta.artists.c_str());
}
break;
case MP_ORDER_ALBUM:
{
//ImGui::NewLine();
if (!meta.meta.album.empty()) {
new_pos = get_ticker_limited_pos(meta.ticker.pos, meta.ticker.tw2, left_limit, right_limit);
ImGui::SetCursorPosX(new_pos);
ImGui::TextColored(color, "%s", meta.meta.album.c_str());
}
}
break;
default: break;
}
for (const auto& fmt : meta.ticker.formatted)
{
if (fmt.text.empty()) continue;
new_pos = get_ticker_limited_pos(meta.ticker.pos, fmt.width, left_limit, right_limit);
ImGui::SetCursorPosX(new_pos);
ImGui::TextColored(color, "%s", fmt.text.c_str());
}
if (!meta.meta.playing) {
@ -340,7 +404,7 @@ void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVe
float display_time = std::chrono::duration<float>(now - logger->last_log_end()).count();
static float display_for = 10.0f;
float alpha;
if(params.background_alpha != 0){
if (params.background_alpha != 0){
if (display_for >= display_time){
alpha = display_time * params.background_alpha;
if (alpha >= params.background_alpha){
@ -365,11 +429,13 @@ void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVe
ImGui::SetNextWindowBgAlpha(params.background_alpha);
}
}
ImGui::Begin("Benchmark", &gui_open, ImGuiWindowFlags_NoDecoration);
static const char* finished = "Logging Finished";
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(finished).x / 2));
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", finished);
ImGui::Dummy(ImVec2(0.0f, 8.0f));
char duration[20];
snprintf(duration, sizeof(duration), "Duration: %.1fs", std::chrono::duration<float>(logger->last_log_end() - logger->last_log_begin()).count());
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(duration).x / 2));
@ -380,6 +446,7 @@ void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVe
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(buffer).x / 2));
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s %.1f", data_.first.c_str(), data_.second);
}
float max = *max_element(benchmark.fps_data.begin(), benchmark.fps_data.end());
ImVec4 plotColor = HUDElements.colors.frametime;
plotColor.w = alpha / params.background_alpha;
@ -398,7 +465,7 @@ ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current)
{
if (current >= data.high_load){
return data.color_high;
}
}
else if (current >= data.med_load){
float diff = float(current - data.med_load) / float(data.high_load - data.med_load);
float x = (data.color_high.x - data.color_med.x) * diff;
@ -448,3 +515,275 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
render_benchmark(data, params, window_size, height, now);
}
}
void init_cpu_stats(overlay_params& params)
{
#ifdef __gnu_linux__
auto& enabled = params.enabled;
enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = cpuStats.Init()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_stats];
enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = cpuStats.GetCpuFile()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_temp];
enabled[OVERLAY_PARAM_ENABLED_cpu_power] = cpuStats.InitCpuPowerData()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_power];
#endif
}
struct pci_bus {
int domain;
int bus;
int slot;
int func;
};
void init_gpu_stats(uint32_t& vendorID, overlay_params& params)
{
//if (!params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats])
// return;
pci_bus pci;
bool pci_bus_parsed = false;
const char *pci_dev = nullptr;
if (!params.pci_dev.empty())
pci_dev = params.pci_dev.c_str();
// for now just checks if pci bus parses correctly, if at all necessary
if (pci_dev) {
if (sscanf(pci_dev, "%04x:%02x:%02x.%x",
&pci.domain, &pci.bus,
&pci.slot, &pci.func) == 4) {
pci_bus_parsed = true;
// reformat back to sysfs file name's and nvml's expected format
// so config file param's value format doesn't have to be as strict
std::stringstream ss;
ss << std::hex
<< std::setw(4) << std::setfill('0') << pci.domain << ":"
<< std::setw(2) << pci.bus << ":"
<< std::setw(2) << pci.slot << "."
<< std::setw(1) << pci.func;
params.pci_dev = ss.str();
pci_dev = params.pci_dev.c_str();
SPDLOG_DEBUG("PCI device ID: '{}'", pci_dev);
} else {
SPDLOG_ERROR("Failed to parse PCI device ID: '{}'", pci_dev);
SPDLOG_ERROR("Specify it as 'domain:bus:slot.func'");
}
}
// NVIDIA or Intel but maybe has Optimus
if (vendorID == 0x8086
|| vendorID == 0x10de) {
if(checkNvidia(pci_dev))
vendorID = 0x10de;
else
params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = false;
}
#ifdef __gnu_linux__
if (vendorID == 0x8086 || vendorID == 0x1002
|| gpu.find("Radeon") != std::string::npos
|| gpu.find("AMD") != std::string::npos) {
string path;
string drm = "/sys/class/drm/";
getAmdGpuInfo_actual = getAmdGpuInfo;
bool using_libdrm = false;
auto dirs = ls(drm.c_str(), "card");
for (auto& dir : dirs) {
path = drm + dir;
SPDLOG_DEBUG("amdgpu path check: {}/device/vendor", path);
string device = read_line(path + "/device/device");
deviceID = strtol(device.c_str(), NULL, 16);
string line = read_line(path + "/device/vendor");
trim(line);
if (line != "0x1002" || !file_exists(path + "/device/gpu_busy_percent"))
continue;
if (pci_bus_parsed && pci_dev) {
string pci_device = read_symlink((path + "/device").c_str());
SPDLOG_DEBUG("PCI device symlink: '{}'", pci_device);
if (!ends_with(pci_device, pci_dev)) {
SPDLOG_DEBUG("skipping GPU, no PCI ID match");
continue;
}
}
SPDLOG_DEBUG("using amdgpu path: {}", path);
#ifdef HAVE_LIBDRM_AMDGPU
int idx = -1;
//TODO make neater
int res = sscanf(path.c_str(), "/sys/class/drm/card%d", &idx);
std::string dri_path = "/dev/dri/card" + std::to_string(idx);
if (!params.enabled[OVERLAY_PARAM_ENABLED_force_amdgpu_hwmon] && res == 1 && amdgpu_open(dri_path.c_str())) {
vendorID = 0x1002;
using_libdrm = true;
getAmdGpuInfo_actual = getAmdGpuInfo_libdrm;
amdgpu_set_sampling_period(params.fps_sampling_period);
SPDLOG_DEBUG("Using libdrm");
// fall through and open sysfs handles for fallback or check DRM version beforehand
} else if (!params.enabled[OVERLAY_PARAM_ENABLED_force_amdgpu_hwmon]) {
SPDLOG_ERROR("Failed to open device '/dev/dri/card{}' with libdrm, falling back to using hwmon sysfs.", idx);
}
#endif
path += "/device";
if (!amdgpu.busy)
amdgpu.busy = fopen((path + "/gpu_busy_percent").c_str(), "r");
if (!amdgpu.vram_total)
amdgpu.vram_total = fopen((path + "/mem_info_vram_total").c_str(), "r");
if (!amdgpu.vram_used)
amdgpu.vram_used = fopen((path + "/mem_info_vram_used").c_str(), "r");
path += "/hwmon/";
string tempFolder;
if (find_folder(path, "hwmon", tempFolder)) {
if (!amdgpu.core_clock)
amdgpu.core_clock = fopen((path + tempFolder + "/freq1_input").c_str(), "r");
if (!amdgpu.memory_clock)
amdgpu.memory_clock = fopen((path + tempFolder + "/freq2_input").c_str(), "r");
if (!amdgpu.temp)
amdgpu.temp = fopen((path + tempFolder + "/temp1_input").c_str(), "r");
if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((path + tempFolder + "/power1_average").c_str(), "r");
vendorID = 0x1002;
break;
}
}
// don't bother then
if (!using_libdrm && !amdgpu.busy && !amdgpu.temp && !amdgpu.vram_total && !amdgpu.vram_used) {
params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = false;
}
}
#endif
if (!params.permit_upload)
SPDLOG_INFO("Uploading is disabled (permit_upload = 0)");
}
void init_system_info(){
#ifdef __gnu_linux__
const char* ld_preload = getenv("LD_PRELOAD");
if (ld_preload)
unsetenv("LD_PRELOAD");
ram = exec("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'");
trim(ram);
cpu = exec("cat /proc/cpuinfo | grep 'model name' | tail -n1 | sed 's/^.*: //' | sed 's/([^)]*)/()/g' | tr -d '(/)'");
trim(cpu);
kernel = exec("uname -r");
trim(kernel);
os = exec("cat /etc/*-release | grep 'PRETTY_NAME' | cut -d '=' -f 2-");
os.erase(remove(os.begin(), os.end(), '\"' ), os.end());
trim(os);
cpusched = read_line("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
const char* mangohud_recursion = getenv("MANGOHUD_RECURSION");
if (!mangohud_recursion) {
setenv("MANGOHUD_RECURSION", "1", 1);
driver = exec("glxinfo -B | grep 'OpenGL version' | sed 's/^.*: //' | sed 's/([^()]*)//g' | tr -s ' '");
trim(driver);
unsetenv("MANGOHUD_RECURSION");
} else {
driver = "MangoHud glxinfo recursion detected";
}
// Get WINE version
wineProcess = get_exe_path();
auto n = wineProcess.find_last_of('/');
string preloader = wineProcess.substr(n + 1);
if (preloader == "wine-preloader" || preloader == "wine64-preloader") {
// Check if using Proton
if (wineProcess.find("/dist/bin/wine") != std::string::npos || wineProcess.find("/files/bin/wine") != std::string::npos) {
stringstream ss;
ss << dirname((char*)wineProcess.c_str()) << "/../../version";
string protonVersion = ss.str();
ss.str(""); ss.clear();
ss << read_line(protonVersion);
std::getline(ss, wineVersion, ' '); // skip first number string
std::getline(ss, wineVersion, ' ');
trim(wineVersion);
string toReplace = "proton-";
size_t pos = wineVersion.find(toReplace);
if (pos != std::string::npos) {
// If found replace
wineVersion.replace(pos, toReplace.length(), "Proton ");
}
else {
// If not found insert for non official proton builds
wineVersion.insert(0, "Proton ");
}
}
else {
char *dir = dirname((char*)wineProcess.c_str());
stringstream findVersion;
findVersion << "\"" << dir << "/wine\" --version";
const char *wine_env = getenv("WINELOADERNOEXEC");
if (wine_env)
unsetenv("WINELOADERNOEXEC");
wineVersion = exec(findVersion.str());
std::cout << "WINE VERSION = " << wineVersion << "\n";
if (wine_env)
setenv("WINELOADERNOEXEC", wine_env, 1);
}
}
else {
wineVersion = "";
}
// check for gamemode and vkbasalt
stringstream ss;
string line;
auto pid = getpid();
string path = "/proc/" + to_string(pid) + "/map_files/";
auto files = exec("ls " + path);
ss << files;
while(std::getline(ss, line, '\n')){
auto file = path + line;
auto sym = read_symlink(file.c_str());
if (sym.find("gamemode") != std::string::npos)
HUDElements.gamemode_bol = true;
if (sym.find("vkbasalt") != std::string::npos)
HUDElements.vkbasalt_bol = true;
if (HUDElements.gamemode_bol && HUDElements.vkbasalt_bol)
break;
}
if (ld_preload)
setenv("LD_PRELOAD", ld_preload, 1);
SPDLOG_DEBUG("Ram:{}", ram);
SPDLOG_DEBUG("Cpu:{}", cpu);
SPDLOG_DEBUG("Kernel:{}", kernel);
SPDLOG_DEBUG("Os:{}", os);
SPDLOG_DEBUG("Gpu:{}", gpu);
SPDLOG_DEBUG("Driver:{}", driver);
SPDLOG_DEBUG("CPU Scheduler:{}", cpusched);
#endif
}
void get_device_name(int32_t vendorID, int32_t deviceID, struct swapchain_stats& sw_stats)
{
#ifdef __gnu_linux__
if (pci_ids.find(vendorID) == pci_ids.end())
parse_pciids();
string desc = pci_ids[vendorID].second[deviceID].desc;
size_t position = desc.find("[");
if (position != std::string::npos) {
desc = desc.substr(position);
string chars = "[]";
for (char c: chars)
desc.erase(remove(desc.begin(), desc.end(), c), desc.end());
}
gpu = sw_stats.gpuName = desc;
trim(sw_stats.gpuName); trim(gpu);
#endif
}

@ -5,7 +5,7 @@
#include <string>
#include <stdint.h>
#include <vector>
#include "imgui.h"
#include <imgui.h>
#include "overlay_params.h"
#include "iostats.h"
#include "timing.hpp"
@ -105,6 +105,7 @@ extern struct benchmark_stats benchmark;
extern ImVec2 real_font_size;
extern std::string wineVersion;
extern std::vector<logData> graph_data;
extern overlay_params _params;
void position_layer(struct swapchain_stats& data, struct overlay_params& params, ImVec2 window_size);
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan);
@ -116,15 +117,15 @@ void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& par
void init_system_info(void);
void FpsLimiter(struct fps_limit& stats);
void get_device_name(int32_t vendorID, int32_t deviceID, struct swapchain_stats& sw_stats);
void calculate_benchmark_data(void *params_void);
void calculate_benchmark_data();
void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font);
void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...);
void center_text(std::string& text);
void center_text(const std::string& text);
ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current);
float get_time_stat(void *_data, int _idx);
#ifdef HAVE_DBUS
void render_mpris_metadata(struct overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing, bool is_main);
void render_mpris_metadata(overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);
#endif
#endif //MANGOHUD_OVERLAY_H

@ -7,6 +7,7 @@
#include <errno.h>
#ifdef __gnu_linux__
#include <wordexp.h>
#include <unistd.h>
#endif
#include "imgui.h"
#include <iostream>
@ -16,6 +17,9 @@
#include <cctype>
#include <array>
#include <functional>
#include <spdlog/spdlog.h>
#include <spdlog/cfg/env.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include "overlay_params.h"
#include "overlay.h"
@ -92,8 +96,8 @@ parse_control(const char *str)
{
int ret = os_socket_listen_abstract(str, 1);
if (ret < 0) {
fprintf(stderr, "ERROR: Couldn't create socket pipe at '%s'\n", str);
fprintf(stderr, "ERROR: '%s'\n", strerror(errno));
SPDLOG_ERROR("Couldn't create socket pipe at '{}'\n", str);
SPDLOG_ERROR("ERROR: '{}'", strerror(errno));
return ret;
}
@ -126,7 +130,7 @@ parse_string_to_keysym_vec(const char *str)
if (xk)
keys.push_back(xk);
else
std::cerr << "MANGOHUD: Unrecognized key: '" << ks << "'\n";
SPDLOG_ERROR("Unrecognized key: '{}'", ks);
}
}
return keys;
@ -167,7 +171,7 @@ parse_fps_limit(const char *str)
try {
as_int = static_cast<uint32_t>(std::stoul(value));
} catch (const std::invalid_argument&) {
std::cerr << "MANGOHUD: invalid fps_limit value: '" << value << "'\n";
SPDLOG_ERROR("invalid fps_limit value: '{}'", value);
continue;
}
@ -221,13 +225,14 @@ parse_load_value(const char *str)
static std::vector<std::string>
parse_str_tokenize(const char *str)
parse_str_tokenize(const char *str, const std::string& delims = ",:+", bool btrim = true)
{
std::vector<std::string> data;
auto tokens = str_tokenize(str);
auto tokens = str_tokenize(str, delims);
std::string token;
for (auto& token : tokens) {
trim(token);
if (btrim)
trim(token);
data.push_back(token);
}
return data;
@ -279,25 +284,6 @@ parse_path(const char *str)
return str;
}
static std::vector<media_player_order>
parse_media_player_order(const char *str)
{
std::vector<media_player_order> order;
auto tokens = str_tokenize(str);
for (auto& token : tokens) {
trim(token);
std::transform(token.begin(), token.end(), token.begin(), ::tolower);
if (token == "title")
order.push_back(MP_ORDER_TITLE);
else if (token == "artist")
order.push_back(MP_ORDER_ARTIST);
else if (token == "album")
order.push_back(MP_ORDER_ALBUM);
}
return order;
}
static std::vector<std::string>
parse_benchmark_percentiles(const char *str)
{
@ -317,17 +303,17 @@ parse_benchmark_percentiles(const char *str)
try {
as_float = parse_float(value, &float_len);
} catch (const std::invalid_argument&) {
std::cerr << "MANGOHUD: invalid benchmark percentile: '" << value << "'\n";
SPDLOG_ERROR("invalid benchmark percentile: '{}'", value);
continue;
}
if (float_len != value.length()) {
std::cerr << "MANGOHUD: invalid benchmark percentile: '" << value << "'\n";
SPDLOG_ERROR("invalid benchmark percentile: '{}'", value);
continue;
}
if (as_float > 100 || as_float < 0) {
std::cerr << "MANGOHUD: benchmark percentile is not between 0 and 100 (" << value << ")\n";
SPDLOG_ERROR("benchmark percentile is not between 0 and 100 ({})", value);
continue;
}
@ -436,7 +422,7 @@ parse_gl_size_query(const char *str)
#define parse_fps_value(s) parse_load_value(s)
#define parse_fps_color(s) parse_load_color(s)
#define parse_battery_color(s) parse_color(s)
#define parse_media_player_format(s) parse_str_tokenize(s, ";", false)
static bool
parse_help(const char *str)
@ -495,9 +481,8 @@ parse_string(const char *s, char *out_param, char *out_value)
}
if (*s && !i) {
fprintf(stderr, "MANGOHUD: syntax error: unexpected '%c' (%i) while "
"parsing a string\n", *s, *s);
fflush(stderr);
SPDLOG_ERROR("syntax error: unexpected '{0:c}' ({0:d}) while "
"parsing a string", *s);
}
return i;
@ -547,7 +532,7 @@ parse_overlay_env(struct overlay_params *params,
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
fprintf(stderr, "Unknown option '%s'\n", key);
SPDLOG_ERROR("Unknown option '{}'", key);
}
}
@ -555,6 +540,12 @@ void
parse_overlay_config(struct overlay_params *params,
const char *env)
{
if (!spdlog::get("MANGOHUD"))
spdlog::set_default_logger(spdlog::stderr_color_mt("MANGOHUD")); // Just to get the name in log
#ifndef NDEBUG
spdlog::set_level(spdlog::level::level_enum::debug);
#endif
spdlog::cfg::load_env_levels();
*params = {};
@ -609,7 +600,7 @@ parse_overlay_config(struct overlay_params *params,
params->cpu_load_color = { 0x39f900, 0xfdfd09, 0xb22222 };
params->font_scale_media_player = 0.55f;
params->log_interval = 100;
params->media_player_order = { MP_ORDER_TITLE, MP_ORDER_ARTIST, MP_ORDER_ALBUM };
params->media_player_format = { "{title}", "{artist}", "{album}" };
params->permit_upload = 0;
params->benchmark_percentiles = { "97", "AVG", "1", "0.1" };
params->gpu_load_value = { 60, 90 };
@ -684,7 +675,7 @@ parse_overlay_config(struct overlay_params *params,
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
fprintf(stderr, "Unknown option '%s'\n", it.first.c_str());
SPDLOG_ERROR("Unknown option '{}'", it.first.c_str());
}
}
@ -772,15 +763,26 @@ parse_overlay_config(struct overlay_params *params,
#ifdef HAVE_DBUS
if (params->enabled[OVERLAY_PARAM_ENABLED_media_player]) {
dbusmgr::dbus_mgr.init(params->media_player_name);
if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_MPRIS))
dbusmgr::dbus_mgr.init_mpris(params->media_player_name);
} else {
dbusmgr::dbus_mgr.deinit();
dbusmgr::dbus_mgr.deinit(dbusmgr::SRV_MPRIS);
main_metadata.meta.valid = false;
}
if (params->enabled[OVERLAY_PARAM_ENABLED_gamemode])
{
if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_GAMEMODE))
HUDElements.gamemode_bol = dbusmgr::dbus_mgr.gamemode_enabled(getpid());
}
else
dbusmgr::dbus_mgr.deinit(dbusmgr::SRV_GAMEMODE);
#endif
if(!params->output_file.empty())
printf("MANGOHUD: output_file is Deprecated, use output_folder instead\n");
if(!params->output_file.empty()) {
SPDLOG_INFO("output_file is deprecated, use output_folder instead");
}
auto real_size = params->font_size * params->font_scale;
real_font_size = ImVec2(real_size, real_size / 2);

@ -36,6 +36,9 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(ram) \
OVERLAY_PARAM_BOOL(swap) \
OVERLAY_PARAM_BOOL(vram) \
OVERLAY_PARAM_BOOL(procmem) \
OVERLAY_PARAM_BOOL(procmem_shared) \
OVERLAY_PARAM_BOOL(procmem_virt) \
OVERLAY_PARAM_BOOL(time) \
OVERLAY_PARAM_BOOL(full) \
OVERLAY_PARAM_BOOL(read_cfg) \
@ -70,6 +73,7 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(gamemode) \
OVERLAY_PARAM_BOOL(battery) \
OVERLAY_PARAM_BOOL(battery_icon) \
OVERLAY_PARAM_BOOL(force_amdgpu_hwmon) \
OVERLAY_PARAM_CUSTOM(fps_sampling_period) \
OVERLAY_PARAM_CUSTOM(output_folder) \
OVERLAY_PARAM_CUSTOM(output_file) \
@ -120,7 +124,7 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(pci_dev) \
OVERLAY_PARAM_CUSTOM(media_player_name) \
OVERLAY_PARAM_CUSTOM(media_player_color) \
OVERLAY_PARAM_CUSTOM(media_player_order) \
OVERLAY_PARAM_CUSTOM(media_player_format) \
OVERLAY_PARAM_CUSTOM(cpu_text) \
OVERLAY_PARAM_CUSTOM(gpu_text) \
OVERLAY_PARAM_CUSTOM(log_interval) \
@ -155,12 +159,6 @@ enum overlay_plots {
OVERLAY_PLOTS_MAX,
};
enum media_player_order {
MP_ORDER_TITLE,
MP_ORDER_ARTIST,
MP_ORDER_ALBUM,
};
enum font_glyph_ranges {
FG_KOREAN = (1u << 0),
FG_CHINESE_FULL = (1u << 1),
@ -235,7 +233,7 @@ struct overlay_params {
std::string cpu_text, gpu_text;
std::vector<std::string> blacklist;
unsigned log_interval, autostart_log;
std::vector<media_player_order> media_player_order;
std::vector<std::string> media_player_format;
std::vector<std::string> benchmark_percentiles;
std::string font_file, font_file_text;
uint32_t font_glyph_ranges;

@ -1,3 +1,4 @@
#include <spdlog/spdlog.h>
#include <string>
#include <iostream>
#include <fstream>
@ -22,12 +23,12 @@ std::istream& get_uncommented_line(std::istream& is, std::string &line)
void parse_pciids()
{
std::ifstream file("/usr/share/hwdata/pci.ids");
if(file.fail()){
std::ifstream file("/usr/share/misc/pci.ids");
std::ifstream file;
file.open("/usr/share/hwdata/pci.ids");
if (file.fail()){
file.open("/usr/share/misc/pci.ids");
if (file.fail())
printf("MANGOHUD: can't find file pci.ids\n");
SPDLOG_ERROR("can't find file pci.ids");
}
std::string line;

@ -1,9 +1,10 @@
#include "shared_x11.h"
#include "loaders/loader_x11.h"
#include <cstdlib>
#include <iostream>
#include <memory>
#include <functional>
#include <spdlog/spdlog.h>
#include "shared_x11.h"
#include "loaders/loader_x11.h"
static std::unique_ptr<Display, std::function<void(Display*)>> display;
@ -16,7 +17,7 @@ bool init_x11() {
return true;
if (!g_x11->IsLoaded()) {
std::cerr << "MANGOHUD: X11 loader failed to load\n";
SPDLOG_ERROR("X11 loader failed to load");
failed = true;
return false;
}
@ -34,7 +35,7 @@ bool init_x11() {
failed = !display;
if (failed)
std::cerr << "MANGOHUD: XOpenDisplay failed to open display '" << displayid << "'\n";
SPDLOG_ERROR("XOpenDisplay failed to open display '{}'", displayid);
return !!display;
}

@ -110,7 +110,7 @@ static float parse_float(const std::string& s, std::size_t* float_len = nullptr)
return ret;
}
static std::vector<std::string> str_tokenize(const std::string& s, const std::string&& delims = ",:+")
static std::vector<std::string> str_tokenize(const std::string& s, const std::string& delims = ",:+")
{
std::vector<std::string> v;
size_t old_n = 0, new_n = 0;

@ -33,10 +33,8 @@
#include <vector>
#include <list>
#include <array>
#ifdef __gnu_linux__
#include <libgen.h>
#include <unistd.h>
#endif
#include <iomanip>
#include <spdlog/spdlog.h>
#include <vulkan/vulkan.h>
#include <vulkan/vk_layer.h>
@ -44,7 +42,6 @@
#include "imgui.h"
#include "overlay.h"
#include "font_default.h"
// #include "util/debug.h"
#include <inttypes.h>
@ -55,26 +52,20 @@
#include "vk_enum_to_str.h"
#include <vulkan/vk_util.h>
#include "string_utils.h"
#include "file_utils.h"
#include "gpu.h"
#include "logging.h"
#include "cpu.h"
#include "memory.h"
#include "notify.h"
#include "blacklist.h"
#include "pci_ids.h"
#include "timing.hpp"
string gpuString,wineVersion,wineProcess;
float offset_x, offset_y, hudSpacing;
int hudFirstRow, hudSecondRow;
VkPhysicalDeviceDriverProperties driverProps = {};
int32_t deviceID;
overlay_params _params {};
#if !defined(_WIN32)
namespace MangoHud { namespace GL {
extern swapchain_stats sw_stats;
}}
#endif
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
@ -218,16 +209,13 @@ static void unmap_object(uint64_t obj)
do { \
VkResult __result = (expr); \
if (__result != VK_SUCCESS) { \
fprintf(stderr, "'%s' line %i failed with %s\n", \
SPDLOG_ERROR("'{}' line {} failed with {}", \
#expr, __LINE__, vk_Result_to_str(__result)); \
} \
} while (0)
/**/
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
static void shutdown_swapchain_font(struct swapchain_data*);
static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
@ -462,245 +450,6 @@ struct overlay_draw *get_overlay_draw(struct swapchain_data *data)
return draw;
}
void init_cpu_stats(overlay_params& params)
{
#ifdef __gnu_linux__
auto& enabled = params.enabled;
enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = cpuStats.Init()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_stats];
enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = cpuStats.GetCpuFile()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_temp];
enabled[OVERLAY_PARAM_ENABLED_cpu_power] = cpuStats.InitCpuPowerData()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_power];
#endif
}
struct PCI_BUS {
int domain;
int bus;
int slot;
int func;
};
void init_gpu_stats(uint32_t& vendorID, overlay_params& params)
{
//if (!params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats])
// return;
PCI_BUS pci;
bool pci_bus_parsed = false;
const char *pci_dev = nullptr;
if (!params.pci_dev.empty())
pci_dev = params.pci_dev.c_str();
// for now just checks if pci bus parses correctly, if at all necessary
if (pci_dev) {
if (sscanf(pci_dev, "%04x:%02x:%02x.%x",
&pci.domain, &pci.bus,
&pci.slot, &pci.func) == 4) {
pci_bus_parsed = true;
// reformat back to sysfs file name's and nvml's expected format
// so config file param's value format doesn't have to be as strict
std::stringstream ss;
ss << std::hex
<< std::setw(4) << std::setfill('0') << pci.domain << ":"
<< std::setw(2) << pci.bus << ":"
<< std::setw(2) << pci.slot << "."
<< std::setw(1) << pci.func;
params.pci_dev = ss.str();
pci_dev = params.pci_dev.c_str();
#ifndef NDEBUG
std::cerr << "MANGOHUD: PCI device ID: '" << pci_dev << "'\n";
#endif
} else {
std::cerr << "MANGOHUD: Failed to parse PCI device ID: '" << pci_dev << "'\n";
std::cerr << "MANGOHUD: Specify it as 'domain:bus:slot.func'\n";
}
}
// NVIDIA or Intel but maybe has Optimus
if (vendorID == 0x8086
|| vendorID == 0x10de) {
if(checkNvidia(pci_dev))
vendorID = 0x10de;
else
params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = false;
}
#ifdef __gnu_linux__
if (vendorID == 0x8086 || vendorID == 0x1002
|| gpu.find("Radeon") != std::string::npos
|| gpu.find("AMD") != std::string::npos) {
string path;
string drm = "/sys/class/drm/";
auto dirs = ls(drm.c_str(), "card");
for (auto& dir : dirs) {
path = drm + dir;
#ifndef NDEBUG
std::cerr << "amdgpu path check: " << path << "/device/vendor" << std::endl;
#endif
string device = read_line(path + "/device/device");
deviceID = strtol(device.c_str(), NULL, 16);
string line = read_line(path + "/device/vendor");
trim(line);
if (line != "0x1002" || !file_exists(path + "/device/gpu_busy_percent"))
continue;
path += "/device";
if (pci_bus_parsed && pci_dev) {
string pci_device = read_symlink(path.c_str());
#ifndef NDEBUG
std::cerr << "PCI device symlink: " << pci_device << "\n";
#endif
if (!ends_with(pci_device, pci_dev)) {
std::cerr << "MANGOHUD: skipping GPU, no PCI ID match\n";
continue;
}
}
#ifndef NDEBUG
std::cerr << "using amdgpu path: " << path << std::endl;
#endif
if (!amdgpu.busy)
amdgpu.busy = fopen((path + "/gpu_busy_percent").c_str(), "r");
if (!amdgpu.vram_total)
amdgpu.vram_total = fopen((path + "/mem_info_vram_total").c_str(), "r");
if (!amdgpu.vram_used)
amdgpu.vram_used = fopen((path + "/mem_info_vram_used").c_str(), "r");
path += "/hwmon/";
string tempFolder;
if (find_folder(path, "hwmon", tempFolder)) {
if (!amdgpu.core_clock)
amdgpu.core_clock = fopen((path + tempFolder + "/freq1_input").c_str(), "r");
if (!amdgpu.memory_clock)
amdgpu.memory_clock = fopen((path + tempFolder + "/freq2_input").c_str(), "r");
if (!amdgpu.temp)
amdgpu.temp = fopen((path + tempFolder + "/temp1_input").c_str(), "r");
if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((path + tempFolder + "/power1_average").c_str(), "r");
vendorID = 0x1002;
break;
}
}
// don't bother then
if (!amdgpu.busy && !amdgpu.temp && !amdgpu.vram_total && !amdgpu.vram_used) {
params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = false;
}
}
#endif
if (!params.permit_upload)
printf("MANGOHUD: Uploading is disabled (permit_upload = 0)\n");
}
void init_system_info(){
#ifdef __gnu_linux__
const char* ld_preload = getenv("LD_PRELOAD");
if (ld_preload)
unsetenv("LD_PRELOAD");
ram = exec("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'");
trim(ram);
cpu = exec("cat /proc/cpuinfo | grep 'model name' | tail -n1 | sed 's/^.*: //' | sed 's/([^)]*)/()/g' | tr -d '(/)'");
trim(cpu);
kernel = exec("uname -r");
trim(kernel);
os = exec("cat /etc/*-release | grep 'PRETTY_NAME' | cut -d '=' -f 2-");
os.erase(remove(os.begin(), os.end(), '\"' ), os.end());
trim(os);
cpusched = read_line("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
const char* mangohud_recursion = getenv("MANGOHUD_RECURSION");
if (!mangohud_recursion) {
setenv("MANGOHUD_RECURSION", "1", 1);
driver = exec("glxinfo -B | grep 'OpenGL version' | sed 's/^.*: //' | sed 's/([^()]*)//g' | tr -s ' '");
trim(driver);
unsetenv("MANGOHUD_RECURSION");
} else {
driver = "MangoHud glxinfo recursion detected";
}
// Get WINE version
wineProcess = get_exe_path();
auto n = wineProcess.find_last_of('/');
string preloader = wineProcess.substr(n + 1);
if (preloader == "wine-preloader" || preloader == "wine64-preloader") {
// Check if using Proton
if (wineProcess.find("/dist/bin/wine") != std::string::npos || wineProcess.find("/files/bin/wine") != std::string::npos) {
stringstream ss;
ss << dirname((char*)wineProcess.c_str()) << "/../../version";
string protonVersion = ss.str();
ss.str(""); ss.clear();
ss << read_line(protonVersion);
std::getline(ss, wineVersion, ' '); // skip first number string
std::getline(ss, wineVersion, ' ');
trim(wineVersion);
string toReplace = "proton-";
size_t pos = wineVersion.find(toReplace);
if (pos != std::string::npos) {
// If found replace
wineVersion.replace(pos, toReplace.length(), "Proton ");
}
else {
// If not found insert for non official proton builds
wineVersion.insert(0, "Proton ");
}
}
else {
char *dir = dirname((char*)wineProcess.c_str());
stringstream findVersion;
findVersion << "\"" << dir << "/wine\" --version";
const char *wine_env = getenv("WINELOADERNOEXEC");
if (wine_env)
unsetenv("WINELOADERNOEXEC");
wineVersion = exec(findVersion.str());
std::cout << "WINE VERSION = " << wineVersion << "\n";
if (wine_env)
setenv("WINELOADERNOEXEC", wine_env, 1);
}
}
else {
wineVersion = "";
}
// check for gamemode and vkbasalt
stringstream ss;
string line;
auto pid = getpid();
string path = "/proc/" + to_string(pid) + "/map_files/";
auto files = exec("ls " + path);
ss << files;
while(std::getline(ss, line, '\n')){
auto file = path + line;
auto sym = read_symlink(file.c_str());
if (sym.find("gamemode") != std::string::npos)
HUDElements.gamemode_bol = true;
if (sym.find("vkbasalt") != std::string::npos)
HUDElements.vkbasalt_bol = true;
if (HUDElements.gamemode_bol && HUDElements.vkbasalt_bol)
break;
}
if (ld_preload)
setenv("LD_PRELOAD", ld_preload, 1);
#ifndef NDEBUG
std::cout << "Ram:" << ram << "\n"
<< "Cpu:" << cpu << "\n"
<< "Kernel:" << kernel << "\n"
<< "Os:" << os << "\n"
<< "Gpu:" << gpu << "\n"
<< "Driver:" << driver << "\n"
<< "CPU Scheduler:" << cpusched << std::endl;
#endif
#endif
}
static void snapshot_swapchain_frame(struct swapchain_data *data)
{
struct device_data *device_data = data->device;
@ -720,6 +469,9 @@ static void compute_swapchain_display(struct swapchain_data *data)
struct device_data *device_data = data->device;
struct instance_data *instance_data = device_data->instance;
if (instance_data->params.no_display)
return;
ImGui::SetCurrentContext(data->imgui_context);
if (HUDElements.colors.update)
HUDElements.convert_colors(instance_data->params);
@ -958,7 +710,7 @@ static void check_fonts(struct swapchain_data* data)
if (params.font_params_hash != data->sw_stats.font_params_hash)
{
std::cerr << "MANGOHUD: recreating font image\n";
SPDLOG_DEBUG("Recreating font image");
VkDescriptorSet desc_set = (VkDescriptorSet)io.Fonts->TexID;
create_fonts(instance_data->params, data->sw_stats.font1, data->sw_stats.font_text);
unsigned char* pixels;
@ -975,14 +727,9 @@ static void check_fonts(struct swapchain_data* data)
desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view);
io.Fonts->SetTexID((ImTextureID)desc_set);
data->font_uploaded = false;
data->sw_stats.font_params_hash = params.font_params_hash;
#ifndef NDEBUG
std::cerr << "MANGOHUD: Default font tex size: " << width << "x" << height << "px (" << (width*height*1) << " bytes)" << "\n";
#endif
SPDLOG_DEBUG("Default font tex size: {}x{}px", width, height);
}
}
@ -1049,10 +796,11 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
unsigned image_index)
{
ImDrawData* draw_data = ImGui::GetDrawData();
if (draw_data->TotalVtxCount == 0)
return NULL;
struct device_data *device_data = data->device;
if (!draw_data || draw_data->TotalVtxCount == 0 || device_data->instance->params.no_display)
return nullptr;
struct overlay_draw *draw = get_overlay_draw(data);
device_data->vtable.ResetCommandBuffer(draw->command_buffer, 0);
@ -1744,22 +1492,6 @@ static struct overlay_draw *before_present(struct swapchain_data *swapchain_data
return draw;
}
void get_device_name(int32_t vendorID, int32_t deviceID, struct swapchain_stats& sw_stats)
{
#ifdef __gnu_linux__
string desc = pci_ids[vendorID].second[deviceID].desc;
size_t position = desc.find("[");
if (position != std::string::npos) {
desc = desc.substr(position);
string chars = "[]";
for (char c: chars)
desc.erase(remove(desc.begin(), desc.end(), c), desc.end());
}
gpu = sw_stats.gpuName = desc;
trim(sw_stats.gpuName); trim(gpu);
#endif
}
static VkResult overlay_CreateSwapchainKHR(
VkDevice device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
@ -1817,11 +1549,8 @@ static VkResult overlay_CreateSwapchainKHR(
std::string deviceName = prop.deviceName;
if (!is_blacklisted()) {
#ifdef __gnu_linux__
parse_pciids();
get_device_name(prop.vendorID, prop.deviceID, swapchain_data->sw_stats);
init_system_info();
#endif
init_gpu_stats(device_data->properties.vendorID, device_data->instance->params);
}
if(driverProps.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY){
swapchain_data->sw_stats.driverName = "NVIDIA";
@ -2119,6 +1848,7 @@ static VkResult overlay_CreateDevice(
if (!is_blacklisted()) {
device_map_queues(device_data, pCreateInfo);
init_gpu_stats(device_data->properties.vendorID, device_data->instance->params);
}
return result;
@ -2164,7 +1894,9 @@ static VkResult overlay_CreateInstance(
else if(engineName == "mesa zink") {
engine = ZINK;
#if !defined(_WIN32)
MangoHud::GL::sw_stats.engine = ZINK;
#endif
}
else if (engineName == "Damavand")
@ -2200,6 +1932,7 @@ static VkResult overlay_CreateInstance(
instance_data_map_physical_devices(instance_data, true);
parse_overlay_config(&instance_data->params, getenv("MANGOHUD_CONFIG"));
_params = instance_data->params;
//check for blacklist item in the config file
for (auto& item : instance_data->params.blacklist) {
@ -2208,6 +1941,7 @@ static VkResult overlay_CreateInstance(
if (!is_blacklisted()) {
#ifdef __gnu_linux__
init_system_info();
instance_data->notifier.params = &instance_data->params;
start_notifier(instance_data->notifier);
#endif
@ -2240,8 +1974,8 @@ static void overlay_DestroyInstance(
struct instance_data *instance_data = FIND(struct instance_data, instance);
instance_data_map_physical_devices(instance_data, false);
instance_data->vtable.DestroyInstance(instance, pAllocator);
if (!is_blacklisted())
#ifdef __gnu_linux__
if (!is_blacklisted())
stop_notifier(instance_data->notifier);
#endif
destroy_instance_data(instance_data);

@ -14,6 +14,7 @@ void init_d3d_shared(){
if (cfg_inited)
return;
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
_params = params;
cfg_inited = true;
// init_cpu_stats(params);
}

@ -6,9 +6,13 @@ set -e; \
mkdir -p /run/systemd; \
echo 'docker' > /run/systemd/container; \
mkdir -p /prep; cd /prep; \
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py; \
if [ -f /usr/bin/python3.5 ]; then \
ln -sf python3.5 /usr/bin/python3; \
curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o get-pip.py; \
else \
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py; \
fi; \
if [ ! -f /usr/bin/unzip ]; then apt-get update; apt-get -y install unzip; fi; \
if [ -f /usr/bin/python3.5 ]; then ln -sf python3.5 /usr/bin/python3; fi; \
python3 ./get-pip.py; \
pip3 install meson mako; \
curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl0_440.64-0ubuntu1_amd64.deb; \

@ -3,7 +3,7 @@ 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/v1/projects/imgui/1.81/1/get_zip
patch_url = https://wrapdb.mesonbuild.com/v2/imgui_1.81-1/get_patch
patch_filename = imgui-1.81-1-wrap.zip
patch_hash = 6d00b442690b6a5c5d8f898311daafbce16d370cf64f53294c3b8c5c661e435f

@ -0,0 +1,12 @@
[wrap-file]
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

@ -1,8 +1,9 @@
[wrap-file]
directory = Vulkan-Headers-1.2.158
source_url = https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.2.158.tar.gz
source_filename = v1.2.158.tar.gz
source_filename = vulkan-headers-1.2.158.tar.gz
source_hash = 53361271cfe274df8782e1e47bdc9e61b7af432ba30acbfe31723f9df2c257f3
patch_url = https://wrapdb.mesonbuild.com/v1/projects/vulkan-headers/1.2.158/1/get_zip
patch_filename = vulkan-headers-1.2.158-1-wrap.zip
patch_hash = 5c791eaecf0b0a71bd1d854dc77ee131a242e14a108fdebd917ffa03491949d2
patch_url = https://wrapdb.mesonbuild.com/v2/vulkan-headers_1.2.158-2/get_patch
patch_filename = vulkan-headers-1.2.158-2-wrap.zip
patch_hash = 860358cf5e73f458cd1e88f8c38116d123ab421d5ce2e4129ec38eaedd820e17

Loading…
Cancel
Save