Compare commits

..

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

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

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

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

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

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

@ -1,70 +0,0 @@
name: Update Meson Version and Recreate Release
on:
release:
types: [published]
jobs:
update-version:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Install GitHub CLI
run: sudo apt-get install -y gh
- name: Extract version from release
id: extract_version
run: echo "version=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
- name: Fetch release description
id: fetch_description
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME=${{ env.version }}
DESCRIPTION=$(gh release view $TAG_NAME --json body -q .body)
echo "description=$DESCRIPTION" >> $GITHUB_ENV
- name: Update meson.build
run: |
VERSION=${{ env.version }}
sed -i "s/^\(\s*version\s*:\s*'\)[^']*'/\1${VERSION}'/" meson.build
- name: Commit changes
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add meson.build
git commit -m "Update version to ${{ env.version }}"
git push origin HEAD:refs/heads/master
- name: Force-update tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME=${{ env.version }}
git tag -fa $TAG_NAME -m "Update tag to include version update"
git push origin --force $TAG_NAME
- name: Recreate release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME=${{ env.version }}
DESCRIPTION=${{ env.description }}
gh release delete $TAG_NAME --yes
gh release create $TAG_NAME --target $(git rev-parse HEAD) --title "$TAG_NAME" --notes "$DESCRIPTION"
- name: Trigger other workflows
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME=${{ env.version }}
gh workflow run .github/workflows/build-source.yml --ref $TAG_NAME
gh workflow run .github/workflows/build-package.yml --ref $TAG_NAME

1
.gitignore vendored

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

@ -21,14 +21,14 @@ A Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and m
- [Normal usage](#normal-usage) - [Normal usage](#normal-usage)
- [OpenGL](#opengl) - [OpenGL](#opengl)
- [Hud configuration](#hud-configuration) - [Hud configuration](#hud-configuration)
- [Environment Variables: **`MANGOHUD_CONFIG`**, **`MANGOHUD_CONFIGFILE`**, and **`MANGOHUD_PRESETSFILE`**](#environment-variables) - [Environment Variables: **`MANGOHUD_CONFIG`** and **`MANGOHUD_CONFIGFILE`**](#environment-variables-mangohud_config-and-mangohud_configfile)
- [Vsync](#vsync) - [Vsync](#vsync)
- [OpenGL Vsync](#opengl-vsync) - [OpenGL Vsync](#opengl-vsync)
- [Vulkan Vsync](#vulkan-vsync) - [Vulkan Vsync](#vulkan-vsync)
- [Keybindings](#keybindings) - [Keybindings](#keybindings)
- [Workarounds](#workarounds) - [Workarounds](#workarounds)
- [FPS logging](#fps-logging) - [FPS logging](#fps-logging)
- [Online visualization: FlightlessMango.com](#online-visualization-flightlessmangocom) - [Online viualization: FlightlessMango.com](#online-viualization-flightlessmangocom)
- [Local visualization: `mangoplot`](#local-visualization-mangoplot) - [Local visualization: `mangoplot`](#local-visualization-mangoplot)
## Installation - Build From Source ## Installation - Build From Source
@ -76,8 +76,6 @@ Install necessary development packages.
- X11 (libx11-dev) - X11 (libx11-dev)
- XNVCtrl (libxnvctrl-dev), optional, use `-Dwith_xnvctrl=disabled` option with `meson` to disable - 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 - D-Bus (libdbus-1-dev), optional, use `-Dwith_dbus=disabled` option with `meson` to disable
- wayland-client
- xcbcommon
Python 3 libraries: Python 3 libraries:
@ -269,13 +267,6 @@ OpenGL games may also need `dlsym` hooking. Add `--dlsym` to your command like `
Some Linux native OpenGL games overrides LD_PRELOAD and stops MangoHud from working. You can sometimes fix this by editing LD_PRELOAD in the start script Some Linux native OpenGL games overrides LD_PRELOAD and stops MangoHud from working. You can sometimes fix this by editing LD_PRELOAD in the start script
`LD_PRELOAD=/path/to/mangohud/lib/` `LD_PRELOAD=/path/to/mangohud/lib/`
## gamescope
To enable mangohud with gamescope you need to install mangoapp.
`gamescope --mangoapp %command%`
Using normal mangohud with gamescope is not support.
## Hud configuration ## Hud configuration
MangoHud comes with a config file which can be used to set configuration options globally or per application. Usually it is installed as `/usr/share/doc/mangohud/MangoHud.conf.example` or [get a copy from here](https://raw.githubusercontent.com/flightlessmango/MangoHud/master/data/MangoHud.conf). MangoHud comes with a config file which can be used to set configuration options globally or per application. Usually it is installed as `/usr/share/doc/mangohud/MangoHud.conf.example` or [get a copy from here](https://raw.githubusercontent.com/flightlessmango/MangoHud/master/data/MangoHud.conf).
@ -298,14 +289,12 @@ You can find an example config in /usr/share/doc/mangohud
--- ---
### Environment Variables ### Environment Variables: **`MANGOHUD_CONFIG`** and **`MANGOHUD_CONFIGFILE`**
You can also customize the hud by using the `MANGOHUD_CONFIG` environment variable while separating different options with a comma. This takes priority over any config file. You can also customize the hud by using the `MANGOHUD_CONFIG` environment variable while separating different options with a comma. This takes priority over any config file.
You can also specify configuration file with `MANGOHUD_CONFIGFILE=/path/to/config` for applications whose names are hard to guess (java, python etc). You can also specify configuration file with `MANGOHUD_CONFIGFILE=/path/to/config` for applications whose names are hard to guess (java, python etc).
You can also specify presets file with `MANGOHUD_PRESETSFILE=/path/to/config`. This is especially useful when running mangohud in a sandbox such as flatpak.
A partial list of parameters are below. See the config file for a complete list. A partial list of parameters are below. See the config file for a complete list.
Parameters that are enabled by default have to be explicitly disabled. These (currently) are `fps`, `frame_timing`, `cpu_stats` (cpu load), `gpu_stats` (gpu load), and each can be disabled by setting the corresponding variable to 0 (e.g., fps=0). Parameters that are enabled by default have to be explicitly disabled. These (currently) are `fps`, `frame_timing`, `cpu_stats` (cpu load), `gpu_stats` (gpu load), and each can be disabled by setting the corresponding variable to 0 (e.g., fps=0).
@ -339,8 +328,6 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `custom_text_center` | Display a custom text centered useful for a header e.g `custom_text_center=FlightLessMango Benchmarks` | | `custom_text_center` | Display a custom text centered useful for a header e.g `custom_text_center=FlightLessMango Benchmarks` |
| `custom_text` | Display a custom text e.g `custom_text=Fsync enabled` | | `custom_text` | Display a custom text e.g `custom_text=Fsync enabled` |
| `debug` | Shows the graph of gamescope app frametimes and latency (only on gamescope obviously) | | `debug` | Shows the graph of gamescope app frametimes and latency (only on gamescope obviously) |
| `device_battery_icon` | Display wirless device battery icon. |
| `device_battery` | Display wireless device battery percent. Currently supported arguments `gamepad` and `mouse` e.g `device_battery=gamepad,mouse` |
| `dynamic_frame_timing` | This changes frame_timing y-axis to correspond with the current maximum and minimum frametime instead of being a static 0-50 | | `dynamic_frame_timing` | This changes frame_timing y-axis to correspond with the current maximum and minimum frametime instead of being a static 0-50 |
| `engine_short_names` | Display a short version of the used engine (e.g. `OGL` instead of `OpenGL`) | | `engine_short_names` | Display a short version of the used engine (e.g. `OGL` instead of `OpenGL`) |
| `engine_version` | Display OpenGL or vulkan and vulkan-based render engine's version | | `engine_version` | Display OpenGL or vulkan and vulkan-based render engine's version |
@ -363,18 +350,17 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `fps_limit` | Limit the apps framerate. Comma-separated list of one or more FPS values. `0` means unlimited | | `fps_limit` | Limit the apps framerate. Comma-separated list of one or more FPS values. `0` means unlimited |
| `fps_only` | Show FPS only. ***Not meant to be used with other display params*** | | `fps_only` | Show FPS only. ***Not meant to be used with other display params*** |
| `fps_sampling_period=` | Time interval between two sampling points for gathering the FPS in milliseconds. Default is `500` | | `fps_sampling_period=` | Time interval between two sampling points for gathering the FPS in milliseconds. Default is `500` |
| `fps_value` | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` | | `fps_value=` | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` |
| `fps_metrics` | Takes a list of decimal values or the value avg, e.g `avg,0.001` |
| `frame_count` | Display frame count | | `frame_count` | Display frame count |
| `frametime` | Display frametime next to FPS text | | `frametime` | Display frametime next to FPS text |
| `fsr` | Display the status of FSR (only works in gamescope) | | `fsr` | Display the status of FSR (only works in gamescope) |
| `hdr` | Display the status of HDR (only works in gamescope) |
| `refresh_rate` | Display the current refresh rate (only works in gamescope) |
| `full` | Enable most of the toggleable parameters (currently excludes `histogram`) | | `full` | Enable most of the toggleable parameters (currently excludes `histogram`) |
| `gamemode` | Show if GameMode is on | | `gamemode` | Show if GameMode is on |
| `gamepad_battery_icon` | Display gamepad battery percent with icon. *Enabled by default* |
| `gamepad_battery` | Display battey of wireless gamepads (xone/xpadneo/ds4) |
| `gpu_color`<br>`cpu_color`<br>`vram_color`<br>`ram_color`<br>`io_color`<br>`engine_color`<br>`frametime_color`<br>`background_color`<br>`text_color`<br>`media_player_color` | Change default colors: `gpu_color=RRGGBB` | | `gpu_color`<br>`cpu_color`<br>`vram_color`<br>`ram_color`<br>`io_color`<br>`engine_color`<br>`frametime_color`<br>`background_color`<br>`text_color`<br>`media_player_color` | Change default colors: `gpu_color=RRGGBB` |
| `gpu_core_clock`<br>`gpu_mem_clock`| Display GPU core/memory frequency | | `gpu_core_clock`<br>`gpu_mem_clock`| Display GPU core/memory frequency |
| `gpu_fan` | GPU fan in rpm on AMD, FAN in percent on NVIDIA | | `gpu_fan` | GPU fan in rpm (only works on AMD GPUs) |
| `gpu_load_change` | Change the color of the GPU load depending on load | | `gpu_load_change` | Change the color of the GPU load depending on load |
| `gpu_load_color` | Set the colors for the gpu load change low,medium and high. e.g `gpu_load_color=0000FF,00FFFF,FF00FF` | | `gpu_load_color` | Set the colors for the gpu load change low,medium and high. e.g `gpu_load_color=0000FF,00FFFF,FF00FF` |
| `gpu_load_value` | Set the values for medium and high load e.g `gpu_load_value=50,90` | | `gpu_load_value` | Set the values for medium and high load e.g `gpu_load_value=50,90` |
@ -418,10 +404,8 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `text_outline_color=` | Set the color of `text_outline`. Default = `000000` | | `text_outline_color=` | Set the color of `text_outline`. Default = `000000` |
| `text_outline_thickness=` | Set the thickness of `text_outline`. Default = `1.5` | | `text_outline_thickness=` | Set the thickness of `text_outline`. Default = `1.5` |
| `throttling_status` | Show if GPU is throttling based on Power, current, temp or "other" (Only shows if throttling is currently happening). Currently disabled by default for Nvidia as it causes lag on 3000 series | | `throttling_status` | Show if GPU is throttling based on Power, current, temp or "other" (Only shows if throttling is currently happening). Currently disabled by default for Nvidia as it causes lag on 3000 series |
| `throttling_status_graph` | Same as `throttling_status` but displays throttling in the frametime graph and only power and temp throttling |
| `time`<br>`time_format=%T` | Display local time. See [std::put_time](https://en.cppreference.com/w/cpp/io/manip/put_time) for formatting help. NOTE: Sometimes apps may set `TZ` (timezone) environment variable to UTC/GMT | | `time`<br>`time_format=%T` | Display local time. See [std::put_time](https://en.cppreference.com/w/cpp/io/manip/put_time) for formatting help. NOTE: Sometimes apps may set `TZ` (timezone) environment variable to UTC/GMT |
| `time_no_label` | Remove the label before time | | `toggle_fps_limit` | Cycle between FPS limits. Defaults to `Shift_L+F1` |
| `toggle_fps_limit` | Cycle between FPS limits (needs at least two values set with `fps_limit`). Defaults to `Shift_L+F1` |
| `toggle_preset` | Cycle between Presets. Defaults to `Shift_R+F10` | | `toggle_preset` | Cycle between Presets. Defaults to `Shift_R+F10` |
| `toggle_hud=`<br>`toggle_logging=` | Modifiable toggle hotkeys. Default are `Shift_R+F12` and `Shift_L+F2`, respectively | | `toggle_hud=`<br>`toggle_logging=` | Modifiable toggle hotkeys. Default are `Shift_R+F12` and `Shift_L+F2`, respectively |
| `toggle_hud_position` | Toggle MangoHud postion. Default is `R_Shift+F11` | | `toggle_hud_position` | Toggle MangoHud postion. Default is `R_Shift+F11` |
@ -435,9 +419,6 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `width=`<br>`height=` | Customizeable HUD dimensions (in pixels) | | `width=`<br>`height=` | Customizeable HUD dimensions (in pixels) |
| `wine_color` | Change color of the wine/proton text | | `wine_color` | Change color of the wine/proton text |
| `wine` | Show current Wine or Proton version in use | | `wine` | Show current Wine or Proton version in use |
| `winesync` | Show wine sync method in use |
| `present_mode` | Shows current vulkan [present mode](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html) or vsync status in opengl |
| `network` | Show network interfaces tx and rx kb/s. You can specify interface with `network=eth0` |
Example: `MANGOHUD_CONFIG=cpu_temp,gpu_temp,position=top-right,height=500,font_size=32` 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. 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.
@ -488,7 +469,7 @@ When you toggle logging (default keybind is `Shift_L+F2`), a file is created wit
Log files can be visualized with two different tools: online and locally. Log files can be visualized with two different tools: online and locally.
### Online visualization: FlightlessMango.com ### Online viualization: FlightlessMango.com
Log files can be (batch) uploaded to [FlightlessMango.com](https://flightlessmango.com/games/user_benchmarks), which will then take care of creating a frametime graph and a summary with 1% min / average framerate / 97th percentile in a table form and a horizontal bar chart form. Log files can be (batch) uploaded to [FlightlessMango.com](https://flightlessmango.com/games/user_benchmarks), which will then take care of creating a frametime graph and a summary with 1% min / average framerate / 97th percentile in a table form and a horizontal bar chart form.
Notes: Notes:

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

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

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

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

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

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

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

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

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

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

@ -3,10 +3,12 @@ c = 'i686-w64-mingw32-gcc'
cpp = 'i686-w64-mingw32-g++' cpp = 'i686-w64-mingw32-g++'
ar = 'i686-w64-mingw32-ar' ar = 'i686-w64-mingw32-ar'
strip = 'i686-w64-mingw32-strip' strip = 'i686-w64-mingw32-strip'
pkg-config = 'i686-w64-mingw32-pkg-config' pkgconfig = 'i686-w64-mingw32-pkg-config'
sh = '/usr/bin/sh' sh = '/usr/bin/sh'
[properties] [properties]
c_link_args = ['-static', '-static-libgcc']
cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++']
needs_exe_wrapper = true needs_exe_wrapper = true
[host_machine] [host_machine]

@ -3,10 +3,12 @@ c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++' cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar' ar = 'x86_64-w64-mingw32-ar'
strip = 'x86_64-w64-mingw32-strip' strip = 'x86_64-w64-mingw32-strip'
pkg-config = 'x86_64-w64-mingw32-pkg-config' pkgconfig = 'x86_64-w64-mingw32-pkg-config'
sh = '/usr/bin/sh' sh = '/usr/bin/sh'
[properties] [properties]
c_link_args = ['-static', '-static-libgcc']
cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++']
needs_exe_wrapper = true needs_exe_wrapper = true
[host_machine] [host_machine]

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

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

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

@ -19,9 +19,6 @@
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "amdgpu.h" #include "amdgpu.h"
#ifdef __linux__
#include "implot.h"
#endif
#define GLFW_EXPOSE_NATIVE_X11 #define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
@ -51,7 +48,7 @@ static uint32_t screenWidth, screenHeight;
static unsigned int get_prop(const char* propName){ static unsigned int get_prop(const char* propName){
Display *x11_display = glfwGetX11Display(); Display *x11_display = glfwGetX11Display();
Atom gamescope_focused = XInternAtom(x11_display, propName, false); Atom gamescope_focused = XInternAtom(x11_display, propName, true);
auto scr = DefaultScreen(x11_display); auto scr = DefaultScreen(x11_display);
auto root = RootWindow(x11_display, scr); auto root = RootWindow(x11_display, scr);
Atom actual; Atom actual;
@ -73,7 +70,7 @@ static unsigned int get_prop(const char* propName){
} }
return i; return i;
} }
return -1; return 0;
} }
static void ctrl_thread(){ static void ctrl_thread(){
@ -133,13 +130,10 @@ static void ctrl_thread(){
bool new_frame = false; bool new_frame = false;
static void gamescope_frametime(uint64_t app_frametime_ns, uint64_t latency_ns){ static void gamescope_frametime(uint64_t app_frametime_ns, uint64_t latency_ns){
if (app_frametime_ns != uint64_t(-1))
{
float app_frametime_ms = app_frametime_ns / 1000000.f; float app_frametime_ms = app_frametime_ns / 1000000.f;
HUDElements.gamescope_debug_app.push_back(app_frametime_ms); HUDElements.gamescope_debug_app.push_back(app_frametime_ms);
if (HUDElements.gamescope_debug_app.size() > 200) if (HUDElements.gamescope_debug_app.size() > 200)
HUDElements.gamescope_debug_app.erase(HUDElements.gamescope_debug_app.begin()); HUDElements.gamescope_debug_app.erase(HUDElements.gamescope_debug_app.begin());
}
float latency_ms = latency_ns / 1000000.f; float latency_ms = latency_ns / 1000000.f;
if (latency_ns == uint64_t(-1)) if (latency_ns == uint64_t(-1))
@ -162,16 +156,11 @@ static void msg_read_thread(){
while (1){ while (1){
// make sure that the message recieved is compatible // make sure that the message recieved is compatible
// and that we're not trying to use variables that don't exist (yet) // and that we're not trying to use variables that don't exist (yet)
size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0); size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0) + sizeof(long);
if (msg_size != -1)
{
if (hdr->version == 1){ if (hdr->version == 1){
if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){ if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){
bool should_new_frame = false; if (!params.no_display || logger->is_active())
if (mangoapp_v1->visible_frametime_ns != ~(0lu) && (!params.no_display || logger->is_active())) {
update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns); update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns);
should_new_frame = true;
}
if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){ if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){
HUDElements.g_fsrUpscale = mangoapp_v1->fsrUpscale; HUDElements.g_fsrUpscale = mangoapp_v1->fsrUpscale;
@ -200,8 +189,6 @@ static void msg_read_thread(){
if (msg_size > offsetof(mangoapp_msg_v1, latency_ns)) if (msg_size > offsetof(mangoapp_msg_v1, latency_ns))
gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns); gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns);
if (should_new_frame)
{
{ {
std::unique_lock<std::mutex> lk(mangoapp_m); std::unique_lock<std::mutex> lk(mangoapp_m);
new_frame = true; new_frame = true;
@ -210,23 +197,16 @@ static void msg_read_thread(){
screenWidth = mangoapp_v1->outputWidth; screenWidth = mangoapp_v1->outputWidth;
screenHeight = mangoapp_v1->outputHeight; screenHeight = mangoapp_v1->outputHeight;
} }
}
} else { } else {
printf("Unsupported mangoapp struct version: %i\n", hdr->version); printf("Unsupported mangoapp struct version: %i\n", hdr->version);
exit(1); exit(1);
} }
} }
else
{
printf("mangoapp: msgrcv returned -1 with error %d - %s\n", errno, strerror(errno));
}
}
} }
static const char *GamescopeOverlayProperty = "GAMESCOPE_EXTERNAL_OVERLAY"; static const char *GamescopeOverlayProperty = "GAMESCOPE_EXTERNAL_OVERLAY";
static GLFWwindow* init(const char* glsl_version){ static GLFWwindow* init(const char* glsl_version){
init_spdlog();
GLFWwindow *window = glfwCreateWindow(1280, 800, "mangoapp overlay window", NULL, NULL); GLFWwindow *window = glfwCreateWindow(1280, 800, "mangoapp overlay window", NULL, NULL);
Display *x11_display = glfwGetX11Display(); Display *x11_display = glfwGetX11Display();
Window x11_window = glfwGetX11Window(window); Window x11_window = glfwGetX11Window(window);
@ -241,9 +221,6 @@ static GLFWwindow* init(const char* glsl_version){
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync glfwSwapInterval(1); // Enable vsync
ImGui::CreateContext(); ImGui::CreateContext();
#ifdef __linux__
ImPlot::CreateContext();
#endif
ImGuiIO& io = ImGui::GetIO(); (void)io; ImGuiIO& io = ImGui::GetIO(); (void)io;
io.IniFilename = NULL; io.IniFilename = NULL;
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
@ -259,11 +236,6 @@ static void shutdown(GLFWwindow* window){
glfwDestroyWindow(window); glfwDestroyWindow(window);
} }
static void get_atom_info(){
HUDElements.hdr_status = get_prop("GAMESCOPE_COLOR_APP_WANTS_HDR_FEEDBACK");
HUDElements.refresh = get_prop("GAMESCOPE_DISPLAY_REFRESH_RATE_FEEDBACK");
}
static bool render(GLFWwindow* window) { static bool render(GLFWwindow* window) {
if (HUDElements.colors.update) if (HUDElements.colors.update)
HUDElements.convert_colors(params); HUDElements.convert_colors(params);
@ -275,7 +247,6 @@ static bool render(GLFWwindow* window) {
overlay_new_frame(params); overlay_new_frame(params);
position_layer(sw_stats, params, window_size); position_layer(sw_stats, params, window_size);
render_imgui(sw_stats, params, window_size, true); render_imgui(sw_stats, params, window_size, true);
get_atom_info();
overlay_end_frame(); overlay_end_frame();
if (screenWidth && screenHeight) if (screenWidth && screenHeight)
glfwSetWindowSize(window, screenWidth, screenHeight); glfwSetWindowSize(window, screenWidth, screenHeight);
@ -324,13 +295,11 @@ int main(int, char**)
window_size = ImVec2(params.width, params.height); window_size = ImVec2(params.width, params.height);
deviceName = (char*)glGetString(GL_RENDERER); deviceName = (char*)glGetString(GL_RENDERER);
sw_stats.deviceName = deviceName; sw_stats.deviceName = deviceName;
SPDLOG_DEBUG("mangoapp deviceName: {}", deviceName);
#define GLX_RENDERER_VENDOR_ID_MESA 0x8183 #define GLX_RENDERER_VENDOR_ID_MESA 0x8183
auto pfn_glXQueryCurrentRendererIntegerMESA = (Bool (*)(int, unsigned int*)) (glfwGetProcAddress("glXQueryCurrentRendererIntegerMESA")); auto pfn_glXQueryCurrentRendererIntegerMESA = (Bool (*)(int, unsigned int*)) (glfwGetProcAddress("glXQueryCurrentRendererIntegerMESA"));
// This will return 0x0 vendorID on NVIDIA so just go to else if (pfn_glXQueryCurrentRendererIntegerMESA) {
if (pfn_glXQueryCurrentRendererIntegerMESA && vendorID != 0x0) {
pfn_glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA, &vendorID); pfn_glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA, &vendorID);
SPDLOG_DEBUG("mangoapp vendorID: {:#x}", vendorID);
} else { } else {
if (deviceName.find("Radeon") != std::string::npos if (deviceName.find("Radeon") != std::string::npos
|| deviceName.find("AMD") != std::string::npos){ || deviceName.find("AMD") != std::string::npos){
@ -341,18 +310,12 @@ int main(int, char**)
vendorID = 0x10de; vendorID = 0x10de;
} }
} }
HUDElements.vendorID = vendorID;
init_gpu_stats(vendorID, 0, params); init_gpu_stats(vendorID, 0, params);
init_system_info(); init_system_info();
sw_stats.engine = EngineTypes::GAMESCOPE; sw_stats.engine = EngineTypes::GAMESCOPE;
std::thread(msg_read_thread).detach(); std::thread(msg_read_thread).detach();
std::thread(ctrl_thread).detach(); std::thread(ctrl_thread).detach();
if(!logger) logger = std::make_unique<Logger>(HUDElements.params); if(!logger) logger = std::make_unique<Logger>(HUDElements.params);
Atom noFocusAtom = XInternAtom(x11_display, "GAMESCOPE_NO_FOCUS", False);
uint32_t value = 1;
XChangeProperty(x11_display, x11_window, noFocusAtom, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&value, 1);
// Main loop // Main loop
while (!glfwWindowShouldClose(window)){ while (!glfwWindowShouldClose(window)){
if (!params.no_display){ if (!params.no_display){

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

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

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

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

@ -6,7 +6,6 @@
namespace fs = ghc::filesystem; namespace fs = ghc::filesystem;
using namespace std; using namespace std;
std::mutex device_lock;
std::vector<device_batt> device_data; std::vector<device_batt> device_data;
std::vector<std::string> list; std::vector<std::string> list;
bool device_found = false; bool device_found = false;
@ -19,7 +18,6 @@ int ds5_count = 0;
int switch_count = 0; int switch_count = 0;
int bitdo_count = 0; int bitdo_count = 0;
int logi_count = 0; //Logitech devices, mice & keyboards etc. int logi_count = 0; //Logitech devices, mice & keyboards etc.
int shield_count = 0;
std::string xbox_paths [2]{"gip","xpadneo"}; std::string xbox_paths [2]{"gip","xpadneo"};
@ -30,7 +28,6 @@ static bool operator<(const device_batt& a, const device_batt& b)
void device_update(const struct overlay_params& params){ void device_update(const struct overlay_params& params){
std::unique_lock<std::mutex> l(device_lock);
fs::path path("/sys/class/power_supply"); fs::path path("/sys/class/power_supply");
list.clear(); list.clear();
xbox_count = 0; xbox_count = 0;
@ -38,7 +35,6 @@ void device_update(const struct overlay_params& params){
ds5_count = 0; ds5_count = 0;
switch_count = 0; switch_count = 0;
bitdo_count = 0; bitdo_count = 0;
shield_count = 0;
for (auto &p : fs::directory_iterator(path)) { for (auto &p : fs::directory_iterator(path)) {
string fileName = p.path().filename(); string fileName = p.path().filename();
//Gamepads //Gamepads
@ -75,14 +71,7 @@ void device_update(const struct overlay_params& params){
device_found = true; device_found = true;
bitdo_count += 1; bitdo_count += 1;
} }
//CHECK NVIDIA SHIELD DEVICES
if (fileName.find("thunderstrike") != std::string::npos) {
list.push_back(p.path());
device_found = true;
shield_count += 1;
} }
}
// Mice and Keyboards // Mice and Keyboards
//CHECK LOGITECH DEVICES //CHECK LOGITECH DEVICES
if (std::find(params.device_battery.begin(), params.device_battery.end(), "mouse") != params.device_battery.end()) { if (std::find(params.device_battery.begin(), params.device_battery.end(), "mouse") != params.device_battery.end()) {
@ -97,7 +86,6 @@ void device_update(const struct overlay_params& params){
void device_info () { void device_info () {
std::unique_lock<std::mutex> l(device_lock);
device_count = 0; device_count = 0;
device_data.clear(); device_data.clear();
//gamepad counters //gamepad counters
@ -106,7 +94,6 @@ void device_info () {
int ds5_counter = 0; int ds5_counter = 0;
int switch_counter = 0; int switch_counter = 0;
int bitdo_counter = 0; int bitdo_counter = 0;
int shield_counter = 0;
for (auto &path : list ) { for (auto &path : list ) {
//Set devices paths //Set devices paths
@ -165,25 +152,14 @@ void device_info () {
device_data[device_count].name = "8BITDO PAD-" + to_string(bitdo_counter + 1); device_data[device_count].name = "8BITDO PAD-" + to_string(bitdo_counter + 1);
bitdo_counter++; bitdo_counter++;
} }
//Shield devices
if (path.find("thunderstrike") != std::string::npos) {
if (shield_count == 1)
device_data[device_count].name = "SHIELD PAD";
else
device_data[device_count].name = "SHIELD PAD-" + to_string(shield_counter + 1);
shield_counter++;
}
} }
// MICE AND KEYBOARDS // MICE AND KEYBOARDS
//Logitech Devices //Logitech Devices
if (check_mouse == true) { if (check_mouse == true) {
if (path.find("hidpp_battery") != std::string::npos) { if (path.find("hidpp_battery") != std::string::npos) {
// Find a good way truncate name or retreive device type before using this if (std::getline(device_name, line)) {
// if (std::getline(device_name, line)) { device_data[device_count].name = line;
// device_data[device_count].name = line; }
// }
device_data[device_count].name = "LOGI MOUSE/KB";
} }
} }

@ -14,7 +14,6 @@ struct device_batt {
}; };
extern std::vector<device_batt> device_data; extern std::vector<device_batt> device_data;
extern std::mutex device_lock;
extern bool device_found; extern bool device_found;
extern int device_count; extern int device_count;

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

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

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

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

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

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

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

@ -19,7 +19,6 @@
#include <glad/glad.h> #include <glad/glad.h>
#include "gl_hud.h" #include "gl_hud.h"
#include "../config.h"
using namespace MangoHud::GL; using namespace MangoHud::GL;
@ -112,7 +111,7 @@ EXPORT_C_(int) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
if (!is_blacklisted()) { if (!is_blacklisted()) {
if (ret) { if (ret) {
imgui_set_context(ctx, gl_wsi::GL_WSI_GLX); imgui_set_context(ctx, gl_wsi::GL_WSI_GLX);
SPDLOG_DEBUG("GL ref count: {}", refcnt.load()); SPDLOG_DEBUG("GL ref count: {}", refcnt);
} }
// Afaik -1 only works with EXT version if it has GLX_EXT_swap_control_tear, maybe EGL_MESA_swap_control_tear someday // Afaik -1 only works with EXT version if it has GLX_EXT_swap_control_tear, maybe EGL_MESA_swap_control_tear someday
@ -131,19 +130,8 @@ EXPORT_C_(int) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
return ret; return ret;
} }
#ifndef GLX_SWAP_INTERVAL_EXT
#define GLX_SWAP_INTERVAL_EXT 0x20F1
#endif
static void do_imgui_swap(void *dpy, void *drawable) static void do_imgui_swap(void *dpy, void *drawable)
{ {
static auto last_time = std::chrono::steady_clock::now();
auto current_time = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = current_time - last_time;
if (HUDElements.vsync == 10 || elapsed_seconds.count() > 5.0)
glx.QueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &HUDElements.vsync);
GLint vp[4]; GLint vp[4];
if (!is_blacklisted()) { if (!is_blacklisted()) {
imgui_create(glx.GetCurrentContext(), gl_wsi::GL_WSI_GLX); imgui_create(glx.GetCurrentContext(), gl_wsi::GL_WSI_GLX);
@ -316,7 +304,7 @@ EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name)
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) { EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
void *real_func = get_glx_proc_address((const char*)procName); void *real_func = get_glx_proc_address((const char*)procName);
void *func = mangohud_find_glx_ptr( (const char*)procName ); void *func = mangohud_find_glx_ptr( (const char*)procName );
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast<const char*>(procName), real_func, func); SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func) if (func && real_func)
return func; return func;
@ -327,7 +315,7 @@ EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) { EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) {
void *real_func = get_glx_proc_address((const char*)procName); void *real_func = get_glx_proc_address((const char*)procName);
void *func = mangohud_find_glx_ptr( (const char*)procName ); void *func = mangohud_find_glx_ptr( (const char*)procName );
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast<const char*>(procName), real_func, func); SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, procName, real_func, func);
if (func && real_func) if (func && real_func)
return func; return func;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,7 +1,6 @@
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <array> #include <array>
#include <algorithm>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "logging.h" #include "logging.h"
#include "overlay.h" #include "overlay.h"
@ -27,8 +26,7 @@ string exec(string command) {
#endif #endif
std::array<char, 128> buffer; std::array<char, 128> buffer;
std::string result; std::string result;
auto deleter = [](FILE* ptr){ pclose(ptr); }; std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
std::unique_ptr<FILE, decltype(deleter)> pipe(popen(command.c_str(), "r"), deleter);
if (!pipe) { if (!pipe) {
return "popen failed!"; return "popen failed!";
} }
@ -66,37 +64,18 @@ static bool compareByFps(const logData &a, const logData &b)
static void writeSummary(string filename){ static void writeSummary(string filename){
auto& logArray = logger->get_log_data(); auto& logArray = logger->get_log_data();
// if the log is stopped/started too fast we might end up with an empty vector.
// in that case, just bail.
if (logArray.size() == 0){
logger->stop_logging();
return;
}
filename = filename.substr(0, filename.size() - 4); filename = filename.substr(0, filename.size() - 4);
filename += "_summary.csv"; filename += "_summary.csv";
SPDLOG_INFO("{}", filename); SPDLOG_INFO("{}", filename);
SPDLOG_DEBUG("Writing summary log file [{}]", filename); SPDLOG_DEBUG("Writing summary log file [{}]", filename);
std::ofstream out(filename, ios::out | ios::app); std::ofstream out(filename, ios::out | ios::app);
if (out){ if (out){
out << "0.1% Min FPS," << "1% Min FPS," << "97% Percentile FPS," << "Average FPS," << "GPU Load," << "CPU Load," << "Average Frame Time," << "Average GPU Temp," << "Average CPU Temp," << "Average VRAM Used," << "Average RAM Used," << "Average Swap Used," << "Peak GPU Load," << "Peak CPU Load," << "Peak GPU Temp," << "Peak CPU Temp," << "Peak VRAM Used," << "Peak RAM Used," << "Peak Swap Used" << "\n"; out << "0.1% Min FPS," << "1% Min FPS," << "97% Percentile FPS," << "Average FPS," << "GPU Load," << "CPU Load" << "\n";
std::vector<logData> sorted = logArray; std::vector<logData> sorted = logArray;
std::sort(sorted.begin(), sorted.end(), compareByFps); std::sort(sorted.begin(), sorted.end(), compareByFps);
float total = 0.0f; float total = 0.0f;
float total_gpu = 0.0f;
float total_cpu = 0.0f; float total_cpu = 0.0f;
int total_gpu_temp = 0.0f; float total_gpu = 0.0f;
int total_cpu_temp = 0.0f;
float total_vram = 0.0f;
float total_ram = 0.0f;
float total_swap = 0.0f;
int peak_gpu = 0.0f;
float peak_cpu = 0.0f;
int peak_gpu_temp = 0.0f;
int peak_cpu_temp = 0.0f;
float peak_vram = 0.0f;
float peak_ram = 0.0f;
float peak_swap = 0.0f;
float result; float result;
float percents[2] = {0.001, 0.01}; float percents[2] = {0.001, 0.01};
for (auto percent : percents){ for (auto percent : percents){
@ -111,66 +90,21 @@ static void writeSummary(string filename){
// 97th percentile // 97th percentile
result = sorted.empty() ? 0.0f : 1000 / sorted[floor(0.97 * (sorted.size() - 1))].frametime; result = sorted.empty() ? 0.0f : 1000 / sorted[floor(0.97 * (sorted.size() - 1))].frametime;
out << fixed << setprecision(1) << result << ","; out << fixed << setprecision(1) << result << ",";
// avg + peak // avg
total = 0; total = 0;
for (auto input : sorted){ for (auto input : sorted){
total = total + input.frametime; total = total + input.frametime;
total_gpu = total_gpu + input.gpu_load;
total_cpu = total_cpu + input.cpu_load; total_cpu = total_cpu + input.cpu_load;
total_gpu_temp = total_gpu_temp + input.gpu_temp; total_gpu = total_gpu + input.gpu_load;
total_cpu_temp = total_cpu_temp + input.cpu_temp;
total_vram = total_vram + input.gpu_vram_used;
total_ram = total_ram + input.ram_used;
total_swap = total_swap + input.swap_used;
peak_gpu = std::max(peak_gpu, input.gpu_load);
peak_cpu = std::max(peak_cpu, input.cpu_load);
peak_gpu_temp = std::max(peak_gpu_temp, input.gpu_temp);
peak_cpu_temp = std::max(peak_cpu_temp, input.cpu_temp);
peak_vram = std::max(peak_vram, input.gpu_vram_used);
peak_ram = std::max(peak_ram, input.ram_used);
peak_swap = std::max(peak_swap, input.swap_used);
} }
// Average FPS
result = 1000 / (total / sorted.size()); result = 1000 / (total / sorted.size());
out << fixed << setprecision(1) << result << ","; out << fixed << setprecision(1) << result << ",";
// GPU Load (Average) // GPU
result = total_gpu / sorted.size(); result = total_gpu / sorted.size();
out << result << ","; out << result << ",";
// CPU Load (Average) // CPU
result = total_cpu / sorted.size(); result = total_cpu / sorted.size();
out << result << ","; out << result;
// Average Frame Time
result = total / sorted.size();
out << result << ",";
// Average GPU Temp
result = total_gpu_temp / sorted.size();
out << result << ",";
// Average CPU Temp
result = total_cpu_temp / sorted.size();
out << result << ",";
// Average VRAM Used
result = total_vram / sorted.size();
out << result << ",";
// Average RAM Used
result = total_ram / sorted.size();
out << result << ",";
// Average Swap Used
result = total_swap / sorted.size();
out << result << ",";
// Peak GPU Load
out << peak_gpu << ",";
// Peak CPU Load
out << peak_cpu << ",";
// Peak GPU Temp
out << peak_gpu_temp << ",";
// Peak CPU Temp
out << peak_cpu_temp << ",";
// Peak VRAM Used
out << peak_vram << ",";
// Peak RAM Used
out << peak_ram << ",";
// Peak Swap Used
out << peak_swap;
} else { } else {
SPDLOG_ERROR("Failed to write log file"); SPDLOG_ERROR("Failed to write log file");
} }
@ -191,7 +125,7 @@ static void writeFileHeaders(ofstream& out){
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_log_versioning]) if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_log_versioning])
out << "--------------------FRAME METRICS--------------------" << endl; out << "--------------------FRAME METRICS--------------------" << endl;
out << "fps," << "frametime," << "cpu_load," << "cpu_power," << "gpu_load," << "cpu_temp," << "gpu_temp," << "gpu_core_clock," << "gpu_mem_clock," << "gpu_vram_used," << "gpu_power," << "ram_used," << "swap_used," << "process_rss," << "elapsed" << endl; out << "fps," << "frametime," << "cpu_load," << "gpu_load," << "cpu_temp," << "gpu_temp," << "gpu_core_clock," << "gpu_mem_clock," << "gpu_vram_used," << "gpu_power," << "ram_used," << "swap_used," << "process_rss," << "elapsed" << endl;
} }
@ -206,7 +140,6 @@ void Logger::writeToFile(){
output_file << logArray.back().fps << ","; output_file << logArray.back().fps << ",";
output_file << logArray.back().frametime << ","; output_file << logArray.back().frametime << ",";
output_file << logArray.back().cpu_load << ","; output_file << logArray.back().cpu_load << ",";
output_file << logArray.back().cpu_power << ",";
output_file << logArray.back().gpu_load << ","; output_file << logArray.back().gpu_load << ",";
output_file << logArray.back().cpu_temp << ","; output_file << logArray.back().cpu_temp << ",";
output_file << logArray.back().gpu_temp << ","; output_file << logArray.back().gpu_temp << ",";
@ -339,9 +272,7 @@ void Logger::calculate_benchmark_data(){
for (auto& point : m_log_array) for (auto& point : m_log_array)
sorted.push_back(point.frametime); sorted.push_back(point.frametime);
std::sort(sorted.begin(), sorted.end(), [](float a, float b) { std::sort(sorted.begin(), sorted.end());
return a > b;
});
benchmark.percentile_data.clear(); benchmark.percentile_data.clear();
benchmark.total = 0.f; benchmark.total = 0.f;
@ -370,14 +301,14 @@ void Logger::calculate_benchmark_data(){
benchmark.percentile_data.push_back({percentile, (1000 / result)}); benchmark.percentile_data.push_back({percentile, (1000 / result)});
} }
string label; string label;
float mins[2] = {0.01f, 0.001f}; float mins[2] = {0.01f, 0.001f}, total;
for (auto percent : mins){ for (auto percent : mins){
if (sorted.empty()) total = 0;
continue; size_t idx = ceil(sorted.size() * percent);
for (size_t i = 0; i < idx; i++){
size_t percentile_pos = sorted.size() * percent; total = total + sorted[i];
percentile_pos = std::min(percentile_pos, sorted.size() - 1); }
float result = 1000 / sorted[percentile_pos]; result = 1000 / (total / idx);
if (percent == 0.001f) if (percent == 0.001f)
label = "0.1%"; label = "0.1%";

@ -17,7 +17,6 @@ struct logData{
double fps; double fps;
float frametime; float frametime;
float cpu_load; float cpu_load;
float cpu_power;
int gpu_load; int gpu_load;
int cpu_temp; int cpu_temp;
int gpu_temp; int gpu_temp;
@ -61,7 +60,6 @@ public:
std::string output_folder; std::string output_folder;
const int64_t log_interval; const int64_t log_interval;
const int64_t log_duration; const int64_t log_duration;
bool autostart_init = false;
private: private:
std::vector<logData> m_log_array; std::vector<logData> m_log_array;

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

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

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

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

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

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

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

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

@ -23,10 +23,7 @@
#include "pci_ids.h" #include "pci_ids.h"
#include "iostats.h" #include "iostats.h"
#include "amdgpu.h" #include "amdgpu.h"
#include "fps_metrics.h"
#include "intel.h"
#include "msm.h"
#include "net.h"
#ifdef __linux__ #ifdef __linux__
#include <libgen.h> #include <libgen.h>
@ -75,7 +72,7 @@ void init_spdlog()
SPDLOG_ERROR("{}", ex.what()); SPDLOG_ERROR("{}", ex.what());
} }
} }
#ifdef DEBUG #ifndef NDEBUG
spdlog::set_level(spdlog::level::level_enum::debug); spdlog::set_level(spdlog::level::level_enum::debug);
#endif #endif
spdlog::cfg::load_env_levels(); spdlog::cfg::load_env_levels();
@ -91,12 +88,6 @@ void init_spdlog()
spdlog::set_level(spdlog::level::from_str(log_level)); spdlog::set_level(spdlog::level::from_str(log_level));
} }
} }
#ifndef DEBUG
} else {
std::string log_level = "err";
transform(log_level.begin(), log_level.end(), log_level.begin(), ::tolower);
spdlog::set_level(spdlog::level::from_str(log_level));
#endif
} }
} }
@ -132,15 +123,13 @@ void update_hw_info(const struct overlay_params& params, uint32_t vendorID)
getAmdGpuInfo(); getAmdGpuInfo();
#ifdef __linux__ #ifdef __linux__
if (gpu_metrics_exists) if (gpu_metrics_exists)
amdgpu_get_metrics(deviceID); amdgpu_get_metrics();
#endif #endif
if (vendorID == 0x10de) if (vendorID == 0x10de)
getNvidiaGpuInfo(params); getNvidiaGpuInfo(params);
#ifdef __linux__ #ifdef __linux__
if (vendorID== 0x8086) if (vendorID== 0x8086)
if (intel) intel->update(); getIntelGpuInfo();
if (vendorID == 0x5143)
if (msm) msm->update();
#endif #endif
} }
@ -175,7 +164,6 @@ void update_hw_info(const struct overlay_params& params, uint32_t vendorID)
currentLogData.cpu_load = cpuStats.GetCPUDataTotal().percent; currentLogData.cpu_load = cpuStats.GetCPUDataTotal().percent;
currentLogData.cpu_temp = cpuStats.GetCPUDataTotal().temp; currentLogData.cpu_temp = cpuStats.GetCPUDataTotal().temp;
currentLogData.cpu_power = cpuStats.GetCPUDataTotal().power;
// Save data for graphs // Save data for graphs
if (graph_data.size() >= kMaxGraphEntries) if (graph_data.size() >= kMaxGraphEntries)
graph_data.pop_front(); graph_data.pop_front();
@ -253,27 +241,17 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru
if (sw_stats.last_present_time) { if (sw_stats.last_present_time) {
sw_stats.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing] = sw_stats.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing] =
frametime_ns; frametime_ns;
frametime_data.push_back(frametime_ms); frametime_data[f_idx] = frametime_ms;
frametime_data.erase(frametime_data.begin());
} }
#ifdef __linux__
if (throttling)
throttling->update();
#endif
frametime = frametime_ms; frametime = frametime_ms;
fps = double(1000 / frametime_ms); fps = double(1000 / frametime_ms);
if (fpsmetrics) fpsmetrics->update(now, fps);
if (elapsed >= params.fps_sampling_period) { if (elapsed >= params.fps_sampling_period) {
if (!hw_update_thread) if (!hw_update_thread)
hw_update_thread = std::make_unique<hw_info_updater>(); hw_update_thread = std::make_unique<hw_info_updater>();
hw_update_thread->update(&params, vendorID); hw_update_thread->update(&params, vendorID);
if (fpsmetrics) fpsmetrics->update_thread();
#ifdef __linux__
if (HUDElements.net) HUDElements.net->update();
#endif
sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed; sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed;
if (params.enabled[OVERLAY_PARAM_ENABLED_time]) { if (params.enabled[OVERLAY_PARAM_ENABLED_time]) {
@ -283,13 +261,6 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru
sw_stats.time = time.str(); sw_stats.time = time.str();
} }
if (params.autostart_log && logger && !logger->autostart_init) {
if ((std::chrono::steady_clock::now() - HUDElements.overlay_start) > std::chrono::seconds(params.autostart_log)){
logger->start_logging();
logger->autostart_init = true;
}
}
sw_stats.n_frames_since_update = 0; sw_stats.n_frames_since_update = 0;
sw_stats.last_fps_update = now; sw_stats.last_fps_update = now;
@ -418,7 +389,9 @@ void RenderOutlinedText(const char* text, ImU32 textColor) {
float outlineThickness = HUDElements.params->text_outline_thickness; float outlineThickness = HUDElements.params->text_outline_thickness;
ImVec2 textSize = ImGui::CalcTextSize(text); ImVec2 textSize = ImGui::CalcTextSize(text);
ImU32 outlineColor = ImGui::ColorConvertFloat4ToU32(HUDElements.colors.text_outline); ImVec4 colorVec4 = ImGui::ColorConvertU32ToFloat4(HUDElements.params->text_outline_color);
colorVec4.w = HUDElements.params->alpha;
ImU32 outlineColor = ImGui::ColorConvertFloat4ToU32(colorVec4);
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
ImDrawList* drawList = ImGui::GetWindowDrawList(); ImDrawList* drawList = ImGui::GetWindowDrawList();
@ -609,9 +582,9 @@ static void render_benchmark(swapchain_stats& data, const struct overlay_params&
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 0.0, 0.0, alpha / params.background_alpha)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 0.0, 0.0, alpha / params.background_alpha));
ImGui::Dummy(ImVec2(0.0f, 8.0f)); ImGui::Dummy(ImVec2(0.0f, 8.0f));
if (params.enabled[OVERLAY_PARAM_ENABLED_histogram]) if (params.enabled[OVERLAY_PARAM_ENABLED_histogram])
ImGui::PlotHistogram("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50)); ImGui::PlotHistogram("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvailWidth(), 50));
else else
ImGui::PlotLines("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50)); ImGui::PlotLines("", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvailWidth(), 50));
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
ImGui::End(); ImGui::End();
} }
@ -667,10 +640,6 @@ void horizontal_separator(struct overlay_params& params) {
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan) void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan)
{ {
{
std::unique_lock<std::mutex> lock(config_mtx);
config_cv.wait(lock, []{ return config_ready; });
}
// data.engine = EngineTypes::GAMESCOPE; // data.engine = EngineTypes::GAMESCOPE;
HUDElements.sw_stats = &data; HUDElements.params = &params; HUDElements.sw_stats = &data; HUDElements.params = &params;
HUDElements.is_vulkan = is_vulkan; HUDElements.is_vulkan = is_vulkan;
@ -695,16 +664,18 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
if(params.enabled[OVERLAY_PARAM_ENABLED_horizontal]) if(params.enabled[OVERLAY_PARAM_ENABLED_horizontal])
table_flags = ImGuiTableFlags_NoClip | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; table_flags = ImGuiTableFlags_NoClip | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
if (!params.no_display && !steam_focused && params.table_columns){ if (!params.no_display && !steam_focused){
ImGui::Begin("Main", &gui_open, ImGuiWindowFlags_NoDecoration); ImGui::Begin("Main", &gui_open, ImGuiWindowFlags_NoDecoration);
if (ImGui::BeginTable("hud", params.table_columns, table_flags )) { if (ImGui::BeginTable("hud", params.table_columns, table_flags )) {
HUDElements.place = 0; HUDElements.place = 0;
for (auto& func : HUDElements.ordered_functions){ for (auto& func : HUDElements.ordered_functions){
if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && func.name != "exec") ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(-3,-3));
if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && func.first != HudElements::_exec)
ImGui::TableNextRow(); ImGui::TableNextRow();
func.run(); func.first();
HUDElements.place += 1; HUDElements.place += 1;
if(!HUDElements.ordered_functions.empty() && params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && HUDElements.ordered_functions.size() != (size_t)HUDElements.place) ImGui::PopStyleVar();
if(!HUDElements.ordered_functions.empty() && params.enabled[OVERLAY_PARAM_ENABLED_horizontal] && func != HUDElements.ordered_functions.back())
horizontal_separator(params); horizontal_separator(params);
} }
@ -712,7 +683,7 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
if (HUDElements.table_columns_count > 0 && HUDElements.table_columns_count < 65 ) if (HUDElements.table_columns_count > 0 && HUDElements.table_columns_count < 65 )
params.table_columns = HUDElements.table_columns_count; params.table_columns = HUDElements.table_columns_count;
if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) { if(!params.enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) {
float content_width = ImGui::GetContentRegionAvail().x - (params.table_columns * 64); float content_width = ImGui::GetContentRegionAvailWidth() - (params.table_columns * 64);
window_size = ImVec2(content_width, params.height); window_size = ImVec2(content_width, params.height);
} }
} }
@ -841,24 +812,10 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
path = drm + dir; path = drm + dir;
drm_dev = dir; drm_dev = dir;
SPDLOG_DEBUG("Intel: using drm device {}", drm_dev); SPDLOG_DEBUG("Intel: using drm device {}", drm_dev);
intel = std::make_unique<Intel>();
break; break;
} }
} }
if (vendorID == 0x5143) {
auto dirs = ls(drm.c_str(), "card");
for (auto& dir : dirs) {
if (dir.find("-") != std::string::npos) {
continue; // filter display adapters
}
path = drm + dir;
drm_dev = dir;
SPDLOG_DEBUG("msm: using drm device {}", drm_dev);
msm = std::make_unique<MSM>();
}
}
if (vendorID == 0x1002 if (vendorID == 0x1002
|| gpu.find("Radeon") != std::string::npos || gpu.find("Radeon") != std::string::npos
|| gpu.find("AMD") != std::string::npos) { || gpu.find("AMD") != std::string::npos) {
@ -910,10 +867,8 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
const std::string device_path = path + "/device"; const std::string device_path = path + "/device";
const std::string gpu_metrics_path = device_path + "/gpu_metrics"; const std::string gpu_metrics_path = device_path + "/gpu_metrics";
if (amdgpu_verify_metrics(gpu_metrics_path)) { if (amdgpu_verify_metrics(gpu_metrics_path)) {
gpu_info.fan_rpm = true;
gpu_metrics_exists = true; gpu_metrics_exists = true;
metrics_path = gpu_metrics_path; metrics_path = gpu_metrics_path;
throttling = std::make_unique<Throttling>();
SPDLOG_DEBUG("Using gpu_metrics of {}", gpu_metrics_path); SPDLOG_DEBUG("Using gpu_metrics of {}", gpu_metrics_path);
} }
@ -956,8 +911,6 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
amdgpu.memory_clock = fopen((hwmon_path + dir + "/freq2_input").c_str(), "r"); amdgpu.memory_clock = fopen((hwmon_path + dir + "/freq2_input").c_str(), "r");
if (!amdgpu.power_usage) if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((hwmon_path + dir + "/power1_average").c_str(), "r"); amdgpu.power_usage = fopen((hwmon_path + dir + "/power1_average").c_str(), "r");
if (!amdgpu.power_usage)
amdgpu.power_usage = fopen((hwmon_path + dir + "/power1_input").c_str(), "r");
if (!amdgpu.fan) if (!amdgpu.fan)
amdgpu.fan = fopen((hwmon_path + dir + "/fan1_input").c_str(), "r"); amdgpu.fan = fopen((hwmon_path + dir + "/fan1_input").c_str(), "r");
} }

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

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

@ -6,8 +6,6 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <cstdint> #include <cstdint>
#include <condition_variable>
#include <mutex>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -87,7 +85,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(hide_fsr_sharpness) \ OVERLAY_PARAM_BOOL(hide_fsr_sharpness) \
OVERLAY_PARAM_BOOL(fan) \ OVERLAY_PARAM_BOOL(fan) \
OVERLAY_PARAM_BOOL(throttling_status) \ OVERLAY_PARAM_BOOL(throttling_status) \
OVERLAY_PARAM_BOOL(throttling_status_graph) \
OVERLAY_PARAM_BOOL(fcat) \ OVERLAY_PARAM_BOOL(fcat) \
OVERLAY_PARAM_BOOL(log_versioning) \ OVERLAY_PARAM_BOOL(log_versioning) \
OVERLAY_PARAM_BOOL(horizontal) \ OVERLAY_PARAM_BOOL(horizontal) \
@ -108,12 +105,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(dynamic_frame_timing) \ OVERLAY_PARAM_BOOL(dynamic_frame_timing) \
OVERLAY_PARAM_BOOL(duration) \ OVERLAY_PARAM_BOOL(duration) \
OVERLAY_PARAM_BOOL(inherit) \ OVERLAY_PARAM_BOOL(inherit) \
OVERLAY_PARAM_BOOL(hdr) \
OVERLAY_PARAM_BOOL(refresh_rate) \
OVERLAY_PARAM_BOOL(frame_timing_detailed) \
OVERLAY_PARAM_BOOL(winesync) \
OVERLAY_PARAM_BOOL(present_mode) \
OVERLAY_PARAM_BOOL(time_no_label) \
OVERLAY_PARAM_CUSTOM(fps_sampling_period) \ OVERLAY_PARAM_CUSTOM(fps_sampling_period) \
OVERLAY_PARAM_CUSTOM(output_folder) \ OVERLAY_PARAM_CUSTOM(output_folder) \
OVERLAY_PARAM_CUSTOM(output_file) \ OVERLAY_PARAM_CUSTOM(output_file) \
@ -142,7 +133,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(toggle_preset) \ OVERLAY_PARAM_CUSTOM(toggle_preset) \
OVERLAY_PARAM_CUSTOM(toggle_fps_limit) \ OVERLAY_PARAM_CUSTOM(toggle_fps_limit) \
OVERLAY_PARAM_CUSTOM(toggle_logging) \ OVERLAY_PARAM_CUSTOM(toggle_logging) \
OVERLAY_PARAM_CUSTOM(reset_fps_metrics) \
OVERLAY_PARAM_CUSTOM(reload_cfg) \ OVERLAY_PARAM_CUSTOM(reload_cfg) \
OVERLAY_PARAM_CUSTOM(upload_log) \ OVERLAY_PARAM_CUSTOM(upload_log) \
OVERLAY_PARAM_CUSTOM(upload_logs) \ OVERLAY_PARAM_CUSTOM(upload_logs) \
@ -163,7 +153,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(text_color) \ OVERLAY_PARAM_CUSTOM(text_color) \
OVERLAY_PARAM_CUSTOM(wine_color) \ OVERLAY_PARAM_CUSTOM(wine_color) \
OVERLAY_PARAM_CUSTOM(battery_color) \ OVERLAY_PARAM_CUSTOM(battery_color) \
OVERLAY_PARAM_CUSTOM(network_color) \
OVERLAY_PARAM_CUSTOM(alpha) \ OVERLAY_PARAM_CUSTOM(alpha) \
OVERLAY_PARAM_CUSTOM(log_duration) \ OVERLAY_PARAM_CUSTOM(log_duration) \
OVERLAY_PARAM_CUSTOM(pci_dev) \ OVERLAY_PARAM_CUSTOM(pci_dev) \
@ -196,8 +185,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(text_outline_thickness) \ OVERLAY_PARAM_CUSTOM(text_outline_thickness) \
OVERLAY_PARAM_CUSTOM(fps_text) \ OVERLAY_PARAM_CUSTOM(fps_text) \
OVERLAY_PARAM_CUSTOM(device_battery) \ OVERLAY_PARAM_CUSTOM(device_battery) \
OVERLAY_PARAM_CUSTOM(fps_metrics) \
OVERLAY_PARAM_CUSTOM(network) \
enum overlay_param_position { enum overlay_param_position {
LAYER_POSITION_TOP_LEFT, LAYER_POSITION_TOP_LEFT,
@ -270,9 +257,7 @@ struct overlay_params {
enum gl_size_query gl_size_query {GL_SIZE_DRAWABLE}; enum gl_size_query gl_size_query {GL_SIZE_DRAWABLE};
bool gl_dont_flip {false}; bool gl_dont_flip {false};
int64_t log_duration, log_interval; int64_t log_duration, log_interval;
unsigned cpu_color, gpu_color, vram_color, ram_color, unsigned cpu_color, gpu_color, vram_color, ram_color, engine_color, io_color, frametime_color, background_color, text_color, wine_color, battery_color;
engine_color, io_color, frametime_color, background_color,
text_color, wine_color, battery_color, network_color;
std::vector<unsigned> gpu_load_color; std::vector<unsigned> gpu_load_color;
std::vector<unsigned> cpu_load_color; std::vector<unsigned> cpu_load_color;
std::vector<unsigned> gpu_load_value; std::vector<unsigned> gpu_load_value;
@ -295,7 +280,6 @@ struct overlay_params {
std::vector<KeySym> upload_log; std::vector<KeySym> upload_log;
std::vector<KeySym> upload_logs; std::vector<KeySym> upload_logs;
std::vector<KeySym> toggle_hud_position; std::vector<KeySym> toggle_hud_position;
std::vector<KeySym> reset_fps_metrics;
std::string time_format, output_folder, output_file; std::string time_format, output_folder, output_file;
std::string pci_dev; std::string pci_dev;
std::string media_player_name; std::string media_player_name;
@ -321,8 +305,6 @@ struct overlay_params {
unsigned text_outline_color; unsigned text_outline_color;
float text_outline_thickness; float text_outline_thickness;
std::vector<std::string> device_battery; std::vector<std::string> device_battery;
std::vector<std::string> fps_metrics;
std::vector<std::string> network;
}; };
const extern char *overlay_param_names[]; const extern char *overlay_param_names[];
@ -332,11 +314,9 @@ void parse_overlay_config(struct overlay_params *params,
void presets(int preset, struct overlay_params *params, bool inherit=false); void presets(int preset, struct overlay_params *params, bool inherit=false);
bool parse_preset_config(int preset, struct overlay_params *params); bool parse_preset_config(int preset, struct overlay_params *params);
void add_to_options(struct overlay_params *params, std::string option, std::string value); void add_to_options(struct overlay_params *params, std::string option, std::string value);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
extern std::mutex config_mtx;
extern std::condition_variable config_cv;
extern bool config_ready;
#endif /* MANGOHUD_OVERLAY_PARAMS_H */ #endif /* MANGOHUD_OVERLAY_PARAMS_H */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save