Merge branch 'develop'

pull/58/head
FlightlessMango 4 years ago
commit 5e6fe9876c

3
.gitmodules vendored

@ -1,3 +1,4 @@
[submodule "modules/ImGui/src"]
path = modules/ImGui/src
url = https://github.com/flightlessmango/ImGui.git
url = https://github.com/ocornut/imgui.git
branch = tables

@ -16,15 +16,15 @@ git clone --recurse-submodules https://github.com/flightlessmango/MangoHud.git
cd MangoHud
```
Then simply run the following command:
Then simply run the following commands:
`./build.sh install`
This will build and copy `libMangoHud.so` & `libMangoHud32.so` to `$HOME/.local/share/MangoHud`, as well as copying the required Vulkan layer configuration files.
`./build.sh build`
<br>`./build.sh package`
<br>`sudo ./build.sh install`
---
If you are running an Ubuntu-like distrobution, Fedora, or Arch, the build script will automatically detect and prompt you to install missing build dependencies. If you run in to any issues with this please report them!
If you are running an Ubuntu-like distribution, Fedora, or Arch, the build script will automatically detect and prompt you to install missing build dependencies. If you run into any issues with this please report them!
## Packaging status
@ -53,7 +53,7 @@ The default config file is installed to `$HOME/.config/MangoHud/MangoHud.conf` a
---
### `MANGOHUD_CONFIG` environment varianble
### `MANGOHUD_CONFIG` environment variable
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.
@ -71,19 +71,38 @@ A partial list of parameters are below. See the config file for a complete list.
| `position=` | Location of the hud: `top-left` (default), `top-right`, `bottom-left`, `bottom-right` |
| `no_display` | Hide the hud by default |
| `toggle_hud=`<br>`toggle_logging=` | Modifiable toggle hotkeys. Default are F12 and F2, respectively. |
Note: Width and Height are set automatically based on the font_size, but can be overridden.
| `reload_cfg=` | Change keybind for reloading the config |
| `time`<br>`time_format=%T` | Displays local time. See [std::put_time](https://en.cppreference.com/w/cpp/io/manip/put_time) for formatting help. |
| `gpu_color`<br>`gpu_color`<br>`vram_color`<br>`ram_color`<br>`io_color`<br>`engine_color`<br>`frametime_color`<br>`background_color`<br>`text_color` | Change default colors: `gpu_color=RRGGBB`|
| `alpha` | Set the opacity of all text and frametime graph `0.0-1.0` |
| `background_alpha` | Set the opacity of the background `0.0-1.0` |
| `read_cfg` | Add to MANGOHUD_CONFIG as first parameter to also load config file. Otherwise only MANGOHUD_CONFIG parameters are used. |
| `output_file` | Define name and location of the output file (Required for logging) |
| `font_file` | Change default font (set location to .TTF/.OTF file ) |
| `log_duration` | Set amount of time the logging will run for (in seconds) |
| `vsync`<br> `gl_vsync` | Set vsync for OpenGL or Vulkan |
Example: `MANGOHUD_CONFIG=cpu_temp,gpu_temp,position=top-right,height=500,font_size=32`
## Environment Variables
Note: Width and Height are set automatically based on the font_size, but can be overridden.
## Vsync
### OpenGL Vsync
- `-1` = Adaptive sync
- `0` = Off
- `1` = On
- `n` = Sync to refresh rate / n.
### Vulkan Vsync
- `0` = Adaptive VSync
- `1` = Off
- `2` = Mailbox (VSync with uncapped FPS)
- `3` = On
- `MANGOHUD_OUTPUT` : Define name and location of the output file (Required for logging)
- `MANGOHUD_FONT`: Change default font (set location to .TTF/.OTF file )
## Keybindings
- `F2` : Toggle Logging
- `F4` : Reload Config
- `F12`: Toggle Hud
## MangoHud FPS logging

@ -11,6 +11,9 @@
### VSYNC [0-3] 0 = adaptive; 1 = off; 2 = mailbox; 3 = on
# vsync=
### OpenGL VSYNC [0-N] 0 = off; >=1 = wait for N v-blanks, N > 1 acts as a fps limiter (fps = display refresh rate / N)
# gl_vsync=
################### VISUAL ###################
### Display the current CPU information
@ -27,6 +30,11 @@ frame_timing
### Display the current system time
# time
### Time formatting examples
# time_format = %H:%M
# time_format = [ %T %F ]
# time_format = %X # locally formatted time, because of limited glyph range, missing characters may show as '?' (e.g. japanese)
### Change the hud font size (default is 24)
font_size=24

@ -1,13 +0,0 @@
#!/bin/bash
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
cd $(dirname "$0")
cp -rv ".local/share/MangoHud" "$XDG_DATA_HOME/"
if [[ ! -f "$XDG_CONFIG_HOME/MangoHud/MangoHud.conf" ]]; then
cp -rv ".config/MangoHud" "$XDG_CONFIG_HOME/"
fi
sed -i "s|libMangoHud.so|$XDG_DATA_HOME/MangoHud/libMangoHud32.so|g" "$XDG_DATA_HOME/vulkan/implicit_layer.d/mangohud32.json"
sed -i "s|libMangoHud.so|$XDG_DATA_HOME/MangoHud/libMangoHud.so|g" "$XDG_DATA_HOME/vulkan/implicit_layer.d/mangohud64.json"

@ -0,0 +1,27 @@
install() {
rm -rf "$HOME/.local/share/MangoHud/"
rm -f "$HOME/.local/share/vulkan/implicit_layer.d/"{mangohud32.json,mangohud64.json}
[ "$UID" -eq 0 ] || exec sudo bash "$0" install
tar -C / -xvf MangoHud-package.tar
ldconfig
echo "MangoHud Installed"
}
uninstall() {
[ "$UID" -eq 0 ] || exec sudo bash "$0" uninstall
rm -rfv "/usr/lib/mangohud"
rm -fv "/usr/share/vulkan/implicit_layer.d/mangohud.json"
rm -fv "/etc/ld.so.conf.d/libmangohud.conf"
rm -fv "/etc/ld.so.conf.d/lib32-libmangohud.conf"
rm -fv "/usr/bin/mangohud"
}
for a in $@; do
case $a in
"install") install;;
"uninstall") uninstall;;
*)
echo "Unrecognized command argument: $a"
echo 'Accepted arguments: "install", "uninstall".'
esac
done

@ -0,0 +1,21 @@
#!/bin/sh
MANGOHUD_LIB_NAME="libMangoHud.so"
if [ "$MANGOHUD_NODLSYM" = "1" ]; then
MANGOHUD_LIB_NAME="libMangoHud_nodlsym.so"
fi
if [ "$#" -eq 0 ]; then
programname=`basename "$0"`
echo "ERROR: No program supplied"
echo
echo "Usage: $programname <program>"
exit 1
fi
# Execute the program under a clean environment
# pass through the overriden LD_PRELOAD environment variables
LD_PRELOAD="${LD_PRELOAD}:${MANGOHUD_LIB_NAME}"
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:@libdir_mangohud@"
exec env MANGOHUD=1 LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" LD_PRELOAD="${LD_PRELOAD}" "$@"

@ -0,0 +1,20 @@
#!/bin/sh
MANGOHUD_LIB_NAME="libMangoHud.so"
if [ "$MANGOHUD_NODLSYM" = "1" ]; then
MANGOHUD_LIB_NAME="libMangoHud_nodlsym.so"
fi
if [ "$#" -eq 0 ]; then
programname=`basename "$0"`
echo "ERROR: No program supplied"
echo
echo "Usage: $programname <program>"
exit 1
fi
# Execute the program under a clean environment
# pass through the overriden LD_PRELOAD environment variables
LD_PRELOAD="${LD_PRELOAD}:${MANGOHUD_LIB_NAME}"
exec env MANGOHUD=1 LD_PRELOAD="${LD_PRELOAD}" "$@"

@ -0,0 +1,23 @@
#!/bin/sh
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
MANGOHUD_LIB_NAME="libMangoHud.so:libMangoHud32.so"
if [ "$MANGOHUD_NODLSYM" = "1" ]; then
MANGOHUD_LIB_NAME="libMangoHud_nodlsym.so:libMangoHud_nodlsym32.so"
fi
if [ "$#" -eq 0 ]; then
programname=`basename "$0"`
echo "ERROR: No program supplied"
echo
echo "Usage: $programname <program>"
exit 1
fi
# Execute the program under a clean environment
# pass through the overriden LD_PRELOAD environment variables
LD_PRELOAD="${LD_PRELOAD}:${MANGOHUD_LIB_NAME}"
LD_LIBRARY_PATH="${XDG_DATA_HOME}/MangoHud"
echo $LD_LIBRARY_PATH
exec env MANGOHUD=1 LD_LIBRARY_PATH="$LD_LIBRARY_PATH" LD_PRELOAD="${LD_PRELOAD}" "$@"

@ -4,7 +4,7 @@ XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
DATA_DIR="$XDG_DATA_HOME/MangoHud"
LAYER="build/release/usr/share/vulkan/implicit_layer.d/mangohud.json"
INSTALL_DIR="build/package/MangoHud"
INSTALL_DIR="build/package/"
IMPLICIT_LAYER_DIR="$XDG_DATA_HOME/vulkan/implicit_layer.d"
VERSION=$(git describe --long --tags --always | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//')
@ -109,14 +109,14 @@ configure() {
dependencies
git submodule update --init --depth 50
if [[ ! -f "build/meson64/build.ninja" ]]; then
meson build/meson64 --libdir lib64 --prefix "$PWD/build/release/usr"
meson build/meson64 --libdir lib/mangohud/lib64 --prefix /usr -Dusing_build_sh=true
fi
if [[ ! -f "build/meson32/build.ninja" ]]; then
export CC="gcc -m32"
export CXX="g++ -m32"
export PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}"
export LLVM_CONFIG="/usr/bin/llvm-config32"
meson build/meson32 --libdir lib32 --prefix "$PWD/build/release/usr"
meson build/meson32 --libdir lib/mangohud/lib32 --prefix /usr -Dmangohud_prefix=lib32- -Dusing_build_sh=true
fi
}
@ -124,44 +124,41 @@ build() {
if [[ ! -f "build/meson64/build.ninja" ]]; then
configure
fi
ninja -C build/meson32 install
ninja -C build/meson64 install
DESTDIR="$PWD/build/release" ninja -C build/meson32 install
DESTDIR="$PWD/build/release" ninja -C build/meson64 install
}
package() {
LIB="build/release/usr/lib64/libMangoHud.so"
LIB32="build/release/usr/lib32/libMangoHud.so"
LIB="build/release/usr/lib/mangohud/lib64/libMangoHud.so"
LIB32="build/release/usr/lib/mangohud/lib32/libMangoHud.so"
if [[ ! -f "$LIB" || "$LIB" -ot "build/meson64/src/libMangoHud.so" ]]; then
build
fi
mkdir -p "$INSTALL_DIR/.local/share/"{MangoHud,vulkan/implicit_layer.d}
mkdir -p "$INSTALL_DIR/.config/MangoHud"
cp "$LIB32" "$INSTALL_DIR/.local/share/MangoHud/libMangoHud32.so"
cp "$LIB" "$INSTALL_DIR/.local/share/MangoHud/libMangoHud.so"
cp "$LAYER" "$INSTALL_DIR/.local/share/vulkan/implicit_layer.d/mangohud64.json"
cp "$LAYER" "$INSTALL_DIR/.local/share/vulkan/implicit_layer.d/mangohud32.json"
cp --preserve=mode "bin/install.sh" "build/package/MangoHud/install.sh"
cp "bin/MangoHud.conf" "$INSTALL_DIR/.config/MangoHud/MangoHud.conf"
cp "bin/MangoHud.conf" "$INSTALL_DIR/.local/share/MangoHud/MangoHud.conf"
sed -i "s|64bit|32bit|g" "$INSTALL_DIR/.local/share/vulkan/implicit_layer.d/mangohud32.json"
tar --numeric-owner --owner=0 --group=0 \
-C build/release -cvf "build/MangoHud-package.tar" .
}
tar -C build/package -cpzf "build/MangoHud-$VERSION.tar.gz" .
release() {
rm build/MangoHud-package.tar
mkdir -p build/MangoHud
package
cp --preserve=mode bin/mangohud-setup.sh build/MangoHud/mangohud-setup.sh
cp build/MangoHud-package.tar build/MangoHud/MangoHud-package.tar
tar --numeric-owner --owner=0 --group=0 \
-C build -czvf build/MangoHud-$VERSION.tar.gz MangoHud
}
install() {
PKG="build/MangoHud-$VERSION.tar.gz"
if [[ ! -f "$PKG" || "$PKG" -ot "build/meson64/src/libMangoHud.so" ]]; then
package
fi
if [[ -f "$XDG_CONFIG_HOME/MangoHud/MangoHud.conf" ]]; then
tar xzf "build/MangoHud-$VERSION.tar.gz" -C "$XDG_DATA_HOME/" "./MangoHud/.local/share/"{MangoHud,vulkan} --strip-components=4
else
tar xzf "build/MangoHud-$VERSION.tar.gz" -C "$XDG_DATA_HOME/" "./MangoHud/.local/share/"{MangoHud,vulkan} --strip-components=4
tar xzf "build/MangoHud-$VERSION.tar.gz" -C "$XDG_CONFIG_HOME/" "./MangoHud/.config/MangoHud" --strip-components=3
rm -rf "$HOME/.local/share/MangoHud/"
rm -f "$HOME/.local/share/vulkan/implicit_layer.d/"{mangohud32.json,mangohud64.json}
if [[ ! -f build/MangoHud-package.tar ]]; then
echo No package found. Run \"$0 package\".
exit 1
fi
sed -i "s|libMangoHud.so|$XDG_DATA_HOME/MangoHud/libMangoHud32.so|g" "$XDG_DATA_HOME/vulkan/implicit_layer.d/mangohud32.json"
sed -i "s|libMangoHud.so|$XDG_DATA_HOME/MangoHud/libMangoHud.so|g" "$XDG_DATA_HOME/vulkan/implicit_layer.d/mangohud64.json"
[ "$UID" -eq 0 ] || exec sudo bash "$0" install
tar -C / -xvf build/MangoHud-package.tar
ldconfig
echo "MangoHud Installed"
}
clean() {
@ -169,8 +166,12 @@ clean() {
}
uninstall() {
rm -rfv "$XDG_DATA_HOME/MangoHud"
rm -fv "$IMPLICIT_LAYER_DIR"/{mangohud64,mangohud32}.json
[ "$UID" -eq 0 ] || exec sudo bash "$0" uninstall
rm -rfv "/usr/lib/mangohud"
rm -fv "/usr/share/vulkan/implicit_layer.d/mangohud.json"
rm -fv "/etc/ld.so.conf.d/libmangohud.conf"
rm -fv "/etc/ld.so.conf.d/lib32-libmangohud.conf"
rm -fv "/usr/bin/mangohud"
}
for a in $@; do
@ -183,6 +184,7 @@ for a in $@; do
"install") install;;
"clean") clean;;
"uninstall") uninstall;;
"release") release;;
*)
echo "Unrecognized command argument: $a"
echo 'Accepted arguments: "pull", "configure", "build", "package", "install", "clean", "uninstall".'

@ -0,0 +1,2 @@
/usr/lib/mangohud/lib32
/usr/lib/mangohud/lib64

@ -0,0 +1 @@
@libdir_mangohud@

@ -18,7 +18,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
project('mangohud',
project('MangoHud',
['c', 'cpp'],
version : 'v1.0.0',
license : 'MIT',
@ -30,6 +30,12 @@ cpp = meson.get_compiler('cpp')
prog_python = import('python').find_installation('python3')
null_dep = dependency('', required : false)
# Needs prefix for configure_file()
libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'), 'mangohud')
if get_option('using_build_sh')
libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'))
endif
pre_args = [
'-D__STDC_CONSTANT_MACROS',
'-D__STDC_FORMAT_MACROS',
@ -206,6 +212,13 @@ vk_enum_to_str = custom_target(
'--outdir', meson.current_build_dir()
],
)
if get_option('using_build_sh')
configure_file(input : 'libmangohud.conf.in',
output : get_option('mangohud_prefix') + 'libmangohud.conf',
configuration : { 'libdir_mangohud' : libdir_mangohud },
install_dir : join_paths(get_option('sysconfdir'), 'ld.so.conf.d'),
)
endif
util_files = files(
'src/mesa/util/os_socket.c',

@ -1,2 +1,4 @@
option('glibcxx_asserts', type : 'boolean', value : false)
option('use_system_vulkan', type : 'feature', value : 'disabled', description: 'Use system vulkan headers instead of the provided ones')
option('mangohud_prefix', type : 'string', value : '', description: 'Add prefix to cross-compiled library, like "lib32-".')
option('using_build_sh', type : 'boolean', value : false, description: 'Add "mangohud" suffix to libdir or not.')

@ -1 +1 @@
Subproject commit 6c1a73774dabd2be64f85543b1286e44632d1905
Subproject commit e628122da006c0e9f7e695592765696d8253cf6f

@ -5,35 +5,27 @@
#include "config.h"
#include "overlay_params.h"
#include "file_utils.h"
#include "string_utils.h"
std::unordered_map<std::string,std::string> options;
void parseConfigLine(std::string line){
if(line.find("#")!=std::string::npos)
{
line = line.erase(line.find("#"),std::string::npos);
}
size_t space = line.find(" ");
while(space!=std::string::npos)
{
line = line.erase(space,1);
space = line.find(" ");
}
space = line.find("\t");
while(space!=std::string::npos)
{
line = line.erase(space,1);
space = line.find("\t");
}
void parseConfigLine(std::string line) {
std::string param, value;
if (line.find("#") != std::string::npos)
line = line.erase(line.find("#"), std::string::npos);
size_t equal = line.find("=");
if(equal==std::string::npos)
{
if (!line.empty())
options[line] = "1";
return;
}
options[line.substr(0, equal)] = line.substr(equal+1);
if (equal == std::string::npos)
value = "1";
else
value = line.substr(equal+1);
param = line.substr(0, equal);
trim(param);
trim(value);
if (!param.empty())
options[param] = value;
}
void parseConfigFile() {
@ -43,9 +35,6 @@ void parseConfigFile() {
std::string env_data = get_data_dir();
std::string env_config = get_config_dir();
if (!env_data.empty())
paths.push_back(env_data + mangohud_dir + "MangoHud.conf");
if (!env_config.empty())
paths.push_back(env_config + mangohud_dir + "MangoHud.conf");
@ -85,7 +74,7 @@ void parseConfigFile() {
std::ifstream stream(*p);
if (!stream.good()) {
// printing just so user has an idea of possible configs
std::cerr << "skipping config: " << *p << std::endl;
std::cerr << "skipping config: " << *p << " [ not found ]" << std::endl;
continue;
}

@ -25,177 +25,184 @@
#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
#endif
#include "file_utils.h"
FILE *cpuTempFile = nullptr;
pthread_t cpuTempThread;
void calculateCPUData(CPUData& cpuData,
unsigned long long int usertime,
unsigned long long int nicetime,
unsigned long long int systemtime,
unsigned long long int idletime,
unsigned long long int ioWait,
unsigned long long int irq,
unsigned long long int softIrq,
unsigned long long int steal,
unsigned long long int guest,
unsigned long long int guestnice)
unsigned long long int usertime,
unsigned long long int nicetime,
unsigned long long int systemtime,
unsigned long long int idletime,
unsigned long long int ioWait,
unsigned long long int irq,
unsigned long long int softIrq,
unsigned long long int steal,
unsigned long long int guest,
unsigned long long int guestnice)
{
// Guest time is already accounted in usertime
usertime = usertime - guest;
nicetime = nicetime - guestnice;
// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
unsigned long long int idlealltime = idletime + ioWait;
unsigned long long int systemalltime = systemtime + irq + softIrq;
unsigned long long int virtalltime = guest + guestnice;
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
// Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
// used in /proc/stat rounds down numbers, it can lead to a case where the
// integer overflow.
#define WRAP_SUBTRACT(a,b) (a > b) ? a - b : 0
cpuData.userPeriod = WRAP_SUBTRACT(usertime, cpuData.userTime);
cpuData.nicePeriod = WRAP_SUBTRACT(nicetime, cpuData.niceTime);
cpuData.systemPeriod = WRAP_SUBTRACT(systemtime, cpuData.systemTime);
cpuData.systemAllPeriod = WRAP_SUBTRACT(systemalltime, cpuData.systemAllTime);
cpuData.idleAllPeriod = WRAP_SUBTRACT(idlealltime, cpuData.idleAllTime);
cpuData.idlePeriod = WRAP_SUBTRACT(idletime, cpuData.idleTime);
cpuData.ioWaitPeriod = WRAP_SUBTRACT(ioWait, cpuData.ioWaitTime);
cpuData.irqPeriod = WRAP_SUBTRACT(irq, cpuData.irqTime);
cpuData.softIrqPeriod = WRAP_SUBTRACT(softIrq, cpuData.softIrqTime);
cpuData.stealPeriod = WRAP_SUBTRACT(steal, cpuData.stealTime);
cpuData.guestPeriod = WRAP_SUBTRACT(virtalltime, cpuData.guestTime);
cpuData.totalPeriod = WRAP_SUBTRACT(totaltime, cpuData.totalTime);
#undef WRAP_SUBTRACT
cpuData.userTime = usertime;
cpuData.niceTime = nicetime;
cpuData.systemTime = systemtime;
cpuData.systemAllTime = systemalltime;
cpuData.idleAllTime = idlealltime;
cpuData.idleTime = idletime;
cpuData.ioWaitTime = ioWait;
cpuData.irqTime = irq;
cpuData.softIrqTime = softIrq;
cpuData.stealTime = steal;
cpuData.guestTime = virtalltime;
cpuData.totalTime = totaltime;
if (cpuData.totalPeriod == 0)
return;
float total = (float)cpuData.totalPeriod;
float v[4];
v[0] = cpuData.nicePeriod * 100.0f / total;
v[1] = cpuData.userPeriod * 100.0f / total;
/* if not detailed */
v[2] = cpuData.systemAllPeriod * 100.0f / total;
v[3] = (cpuData.stealPeriod + cpuData.guestPeriod) * 100.0f / total;
//cpuData.percent = std::clamp(v[0]+v[1]+v[2]+v[3], 0.0f, 100.0f);
cpuData.percent = std::min(std::max(v[0]+v[1]+v[2]+v[3], 0.0f), 100.0f);
// Guest time is already accounted in usertime
usertime = usertime - guest;
nicetime = nicetime - guestnice;
// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
unsigned long long int idlealltime = idletime + ioWait;
unsigned long long int systemalltime = systemtime + irq + softIrq;
unsigned long long int virtalltime = guest + guestnice;
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
// Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
// used in /proc/stat rounds down numbers, it can lead to a case where the
// integer overflow.
#define WRAP_SUBTRACT(a,b) (a > b) ? a - b : 0
cpuData.userPeriod = WRAP_SUBTRACT(usertime, cpuData.userTime);
cpuData.nicePeriod = WRAP_SUBTRACT(nicetime, cpuData.niceTime);
cpuData.systemPeriod = WRAP_SUBTRACT(systemtime, cpuData.systemTime);
cpuData.systemAllPeriod = WRAP_SUBTRACT(systemalltime, cpuData.systemAllTime);
cpuData.idleAllPeriod = WRAP_SUBTRACT(idlealltime, cpuData.idleAllTime);
cpuData.idlePeriod = WRAP_SUBTRACT(idletime, cpuData.idleTime);
cpuData.ioWaitPeriod = WRAP_SUBTRACT(ioWait, cpuData.ioWaitTime);
cpuData.irqPeriod = WRAP_SUBTRACT(irq, cpuData.irqTime);
cpuData.softIrqPeriod = WRAP_SUBTRACT(softIrq, cpuData.softIrqTime);
cpuData.stealPeriod = WRAP_SUBTRACT(steal, cpuData.stealTime);
cpuData.guestPeriod = WRAP_SUBTRACT(virtalltime, cpuData.guestTime);
cpuData.totalPeriod = WRAP_SUBTRACT(totaltime, cpuData.totalTime);
#undef WRAP_SUBTRACT
cpuData.userTime = usertime;
cpuData.niceTime = nicetime;
cpuData.systemTime = systemtime;
cpuData.systemAllTime = systemalltime;
cpuData.idleAllTime = idlealltime;
cpuData.idleTime = idletime;
cpuData.ioWaitTime = ioWait;
cpuData.irqTime = irq;
cpuData.softIrqTime = softIrq;
cpuData.stealTime = steal;
cpuData.guestTime = virtalltime;
cpuData.totalTime = totaltime;
if (cpuData.totalPeriod == 0)
return;
float total = (float)cpuData.totalPeriod;
float v[4];
v[0] = cpuData.nicePeriod * 100.0f / total;
v[1] = cpuData.userPeriod * 100.0f / total;
/* if not detailed */
v[2] = cpuData.systemAllPeriod * 100.0f / total;
v[3] = (cpuData.stealPeriod + cpuData.guestPeriod) * 100.0f / total;
//cpuData.percent = std::clamp(v[0]+v[1]+v[2]+v[3], 0.0f, 100.0f);
cpuData.percent = std::min(std::max(v[0]+v[1]+v[2]+v[3], 0.0f), 100.0f);
}
CPUStats::CPUStats()
{
m_inited = Init();
}
bool CPUStats::Init()
{
std::string line;
std::ifstream file (PROCSTATFILE);
bool first = true;
m_cpuData.clear();
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
return false;
}
do {
if (!std::getline(file, line)) {
std::cerr << "Failed to read all of " << PROCSTATFILE << std::endl;
return false;
} else if (starts_with(line, "cpu")) {
if (first) {
first =false;
continue;
}
CPUData cpu = {};
cpu.totalTime = 1;
cpu.totalPeriod = 1;
m_cpuData.push_back(cpu);
} else if (starts_with(line, "btime ")) {
// C++ way, kind of noisy
//std::istringstream token( line );
//std::string s;
//token >> s;
//token >> m_boottime;
// assume that if btime got read, that everything else is OK too
sscanf(line.c_str(), "btime %lld\n", &m_boottime);
break;
}
} while(true);
UpdateCPUData();
return true;
if (m_inited)
return true;
CPUStats::GetCpuFile();
std::string line;
std::ifstream file (PROCSTATFILE);
bool first = true;
m_cpuData.clear();
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
return false;
}
do {
if (!std::getline(file, line)) {
std::cerr << "Failed to read all of " << PROCSTATFILE << std::endl;
return false;
} else if (starts_with(line, "cpu")) {
if (first) {
first =false;
continue;
}
CPUData cpu = {};
cpu.totalTime = 1;
cpu.totalPeriod = 1;
m_cpuData.push_back(cpu);
} else if (starts_with(line, "btime ")) {
// C++ way, kind of noisy
//std::istringstream token( line );
//std::string s;
//token >> s;
//token >> m_boottime;
// assume that if btime got read, that everything else is OK too
sscanf(line.c_str(), "btime %lld\n", &m_boottime);
break;
}
} while(true);
m_inited = true;
return UpdateCPUData();
}
//TODO take sampling interval into account?
bool CPUStats::UpdateCPUData()
{
CPUStats::UpdateCoreMhz();
unsigned long long int usertime, nicetime, systemtime, idletime;
unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
int cpuid = -1;
if (!m_inited)
return false;
std::string line;
std::ifstream file (PROCSTATFILE);
bool ret = false;
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
return false;
}
do {
if (!std::getline(file, line)) {
break;
} else if (!ret && sscanf(line.c_str(), "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
&usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 10) {
ret = true;
calculateCPUData(m_cpuDataTotal, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
} else if (sscanf(line.c_str(), "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
&cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 11) {
//std::cerr << "Parsing 'cpu" << cpuid << "' line:" << line << std::endl;
if (!ret) {
//std::cerr << "Failed to parse 'cpu' line" << std::endl;
std::cerr << "Failed to parse 'cpu' line:" << line << std::endl;
return false;
}
if (cpuid < 0 /* can it? */ || (size_t)cpuid > m_cpuData.size()) {
std::cerr << "Cpu id '" << cpuid << "' is out of bounds" << std::endl;
return false;
}
CPUData& cpuData = m_cpuData[cpuid];
calculateCPUData(cpuData, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
cpuid = -1;
} else {
break;
}
} while(true);
m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size();
m_updatedCPUs = true;
return ret;
CPUStats::UpdateCpuTemp();
unsigned long long int usertime, nicetime, systemtime, idletime;
unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
int cpuid = -1;
if (!m_inited)
return false;
std::string line;
std::ifstream file (PROCSTATFILE);
bool ret = false;
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
return false;
}
do {
if (!std::getline(file, line)) {
break;
} else if (!ret && sscanf(line.c_str(), "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
&usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 10) {
ret = true;
calculateCPUData(m_cpuDataTotal, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
} else if (sscanf(line.c_str(), "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
&cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 11) {
//std::cerr << "Parsing 'cpu" << cpuid << "' line:" << line << std::endl;
if (!ret) {
//std::cerr << "Failed to parse 'cpu' line" << std::endl;
std::cerr << "Failed to parse 'cpu' line:" << line << std::endl;
return false;
}
if (cpuid < 0 /* can it? */ || (size_t)cpuid > m_cpuData.size()) {
std::cerr << "Cpu id '" << cpuid << "' is out of bounds" << std::endl;
return false;
}
CPUData& cpuData = m_cpuData[cpuid];
calculateCPUData(cpuData, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
cpuid = -1;
} else {
break;
}
} while(true);
m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size();
m_updatedCPUs = true;
return ret;
}
bool CPUStats::UpdateCoreMhz() {
@ -214,4 +221,40 @@ bool CPUStats::UpdateCoreMhz() {
return true;
}
bool CPUStats::UpdateCpuTemp() {
m_cpuDataTotal.temp = 0;
rewind(cpuTempFile);
fflush(cpuTempFile);
if (fscanf(cpuTempFile, "%d", &m_cpuDataTotal.temp) != 1)
return false;
m_cpuDataTotal.temp /= 1000;
return true;
}
bool CPUStats::GetCpuFile() {
std::string name, path;
std::string hwmon = "/sys/class/hwmon/";
auto dirs = ls(hwmon.c_str());
for (auto& dir : dirs) {
path = hwmon + dir;
name = read_line(path + "/name");
#ifndef NDEBUG
std::cerr << "hwmon: sensor name: " << name << std::endl;
#endif
if (name == "coretemp" || name == "k10temp" || name == "zenpower") {
path += "/temp1_input";
break;
}
}
if (!file_exists(path)) {
std::cerr << "MANGOHUD: Could not find cpu temp sensor location" << std::endl;
} else {
cpuTempFile = fopen(path.c_str(), "r");
}
return true;
}
CPUStats cpuStats;

@ -2,63 +2,66 @@
#include <cstdint>
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
unsigned long long int systemTime;
unsigned long long int systemAllTime;
unsigned long long int idleAllTime;
unsigned long long int idleTime;
unsigned long long int niceTime;
unsigned long long int ioWaitTime;
unsigned long long int irqTime;
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
unsigned long long int totalTime;
unsigned long long int userTime;
unsigned long long int systemTime;
unsigned long long int systemAllTime;
unsigned long long int idleAllTime;
unsigned long long int idleTime;
unsigned long long int niceTime;
unsigned long long int ioWaitTime;
unsigned long long int irqTime;
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
unsigned long long int systemAllPeriod;
unsigned long long int idleAllPeriod;
unsigned long long int idlePeriod;
unsigned long long int nicePeriod;
unsigned long long int ioWaitPeriod;
unsigned long long int irqPeriod;
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
float percent;
int mhz;
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
unsigned long long int systemAllPeriod;
unsigned long long int idleAllPeriod;
unsigned long long int idlePeriod;
unsigned long long int nicePeriod;
unsigned long long int ioWaitPeriod;
unsigned long long int irqPeriod;
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
float percent;
int mhz;
int temp;
} CPUData;
class CPUStats
{
public:
CPUStats();
bool Init();
bool Updated()
{
return m_updatedCPUs;
}
CPUStats();
bool Init();
bool Updated()
{
return m_updatedCPUs;
}
bool UpdateCPUData();
bool UpdateCoreMhz();
double GetCPUPeriod() { return m_cpuPeriod; }
bool UpdateCPUData();
bool UpdateCoreMhz();
bool UpdateCpuTemp();
bool GetCpuFile();
double GetCPUPeriod() { return m_cpuPeriod; }
const std::vector<CPUData>& GetCPUData() const {
return m_cpuData;
}
const CPUData& GetCPUDataTotal() const {
return m_cpuDataTotal;
}
const std::vector<CPUData>& GetCPUData() const {
return m_cpuData;
}
const CPUData& GetCPUDataTotal() const {
return m_cpuDataTotal;
}
private:
unsigned long long int m_boottime = 0;
std::vector<CPUData> m_cpuData;
CPUData m_cpuDataTotal {};
std::vector<int> m_coreMhz;
double m_cpuPeriod = 0;
bool m_updatedCPUs = false; // TODO use caching or just update?
bool m_inited = false;
unsigned long long int m_boottime = 0;
std::vector<CPUData> m_cpuData;
CPUData m_cpuDataTotal {};
std::vector<int> m_coreMhz;
double m_cpuPeriod = 0;
bool m_updatedCPUs = false; // TODO use caching or just update?
bool m_inited = false;
};
extern CPUStats cpuStats;

@ -1,124 +0,0 @@
#include <cmath>
#include <iomanip>
#include <array>
#include <vector>
#include <algorithm>
#include <iterator>
#include <thread>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include <regex>
#include "nvidia_info.h"
#include "memory.h"
using namespace std;
int gpuLoad = 0, gpuTemp = 0, cpuTemp = 0;
FILE *amdGpuFile = nullptr, *amdTempFile = nullptr, *cpuTempFile = nullptr, *amdGpuVramTotalFile = nullptr, *amdGpuVramUsedFile = nullptr;
float gpuMemUsed = 0, gpuMemTotal = 0;
int numCpuCores = std::thread::hardware_concurrency();
pthread_t cpuThread, gpuThread, cpuInfoThread;
struct amdGpu {
int load;
int temp;
int64_t memoryUsed;
int64_t memoryTotal;
};
extern struct amdGpu amdgpu;
string exec(string command) {
char buffer[128];
string result = "";
// Open pipe to file
FILE* pipe = popen(command.c_str(), "r");
if (!pipe) {
return "popen failed!";
}
// read till end of process:
while (!feof(pipe)) {
// use buffer to read and add to result
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
void *cpuInfo(void *){
rewind(cpuTempFile);
fflush(cpuTempFile);
if (fscanf(cpuTempFile, "%d", &cpuTemp) != 1)
cpuTemp = 0;
cpuTemp /= 1000;
pthread_detach(cpuInfoThread);
return NULL;
}
void *getNvidiaGpuInfo(void *){
if (!nvmlSuccess)
checkNvidia();
if (nvmlSuccess){
getNvidiaInfo();
gpuLoad = nvidiaUtilization.gpu;
gpuTemp = nvidiaTemp;
gpuMemUsed = float(nvidiaMemory.used / (1024 * 1024)) / 1000;
}
pthread_detach(gpuThread);
return NULL;
}
void *getAmdGpuUsage(void *){
if (amdGpuFile) {
rewind(amdGpuFile);
fflush(amdGpuFile);
if (fscanf(amdGpuFile, "%d", &amdgpu.load) != 1)
amdgpu.load = 0;
gpuLoad = amdgpu.load;
}
if (amdTempFile) {
rewind(amdTempFile);
fflush(amdTempFile);
if (fscanf(amdTempFile, "%d", &amdgpu.temp) != 1)
amdgpu.temp = 0;
amdgpu.temp /= 1000;
gpuTemp = amdgpu.temp;
}
if (amdGpuVramTotalFile) {
rewind(amdGpuVramTotalFile);
fflush(amdGpuVramTotalFile);
if (fscanf(amdGpuVramTotalFile, "%" PRId64, &amdgpu.memoryTotal) != 1)
amdgpu.memoryTotal = 0;
amdgpu.memoryTotal /= (1024 * 1024);
gpuMemTotal = amdgpu.memoryTotal;
}
if (amdGpuVramUsedFile) {
rewind(amdGpuVramUsedFile);
fflush(amdGpuVramUsedFile);
if (fscanf(amdGpuVramUsedFile, "%" PRId64, &amdgpu.memoryUsed) != 1)
amdgpu.memoryUsed = 0;
amdgpu.memoryUsed /= (1024 * 1024);
gpuMemUsed = float(amdgpu.memoryUsed) / 1000;
}
pthread_detach(gpuThread);
return NULL;
}

@ -0,0 +1,23 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void * glXCreateContext(void *, void *, void *, int);
void glXDestroyContext(void *, void*);
void glXSwapBuffers(void*, void*);
void glXSwapIntervalEXT(void*, void*, int);
int glXSwapIntervalSGI(int);
int glXSwapIntervalMESA(unsigned int);
int glXGetSwapIntervalMESA(void);
bool glXMakeCurrent(void*, void*, void*);
void* glXGetProcAddress(const unsigned char*);
void* glXGetProcAddressARB(const unsigned char*);
unsigned int eglSwapBuffers( void*, void* );
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,627 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2020-01-07: OpenGL: Added support for glbindings OpenGL loader.
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
// 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
//----------------------------------------
// OpenGL GLSL GLSL
// version version string
//----------------------------------------
// 2.0 110 "#version 110"
// 2.1 120 "#version 120"
// 3.0 130 "#version 130"
// 3.1 140 "#version 140"
// 3.2 150 "#version 150"
// 3.3 330 "#version 330 core"
// 4.0 400 "#version 400 core"
// 4.1 410 "#version 410 core"
// 4.2 420 "#version 410 core"
// 4.3 430 "#version 430 core"
// ES 2.0 100 "#version 100" = WebGL 1.0
// ES 3.0 300 "#version 300 es" = WebGL 2.0
//----------------------------------------
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <stdint.h> // intptr_t
#include <GL/gl3w.h>
#define GL_CLIP_ORIGIN 0x935C
#define GL_NEGATIVE_ONE_TO_ONE 0x935E
#define GL_ZERO_TO_ONE 0x935F
#define GL_CLIP_DEPTH_MODE 0x935D
void* get_glx_proc_address(const char* name);
void (*glClipControl)(int origin, int depth);
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0
#else
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1
#endif
// OpenGL Data
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries.
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
static GLuint g_FontTexture = 0;
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
glClipControl = reinterpret_cast<decltype(glClipControl)> (get_glx_proc_address("glClipControl"));
// Query for GL version
#if !defined(IMGUI_IMPL_OPENGL_ES2)
glsl_version = "#version 130";
GLint major, minor;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
g_GlVersion = major * 1000 + minor;
printf("Version: %d.%d\n", major, minor);
if (major >= 4 && minor >= 1)
glsl_version = "#version 410";
else if (major > 3 || (major == 3 && minor >= 2))
glsl_version = "#version 150";
#else
g_GlVersion = 2000; // GLES 2
#endif
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3";
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 3200)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
if (glsl_version == NULL)
glsl_version = "#version 130";
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n");
// Make a dummy GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
ImGui_ImplOpenGL3_DestroyDeviceObjects();
}
void ImGui_ImplOpenGL3_NewFrame()
{
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
const float ortho_projection[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
};
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifdef GL_SAMPLER_BINDING
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
#endif
(void)vertex_array_object;
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(vertex_array_object);
#endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
glEnableVertexAttribArray(g_AttribLocationVtxPos);
glEnableVertexAttribArray(g_AttribLocationVtxUV);
glEnableVertexAttribArray(g_AttribLocationVtxColor);
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
}
// OpenGL3 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0)
return;
// Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
#ifdef GL_SAMPLER_BINDING
GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
#endif
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);
#endif
#ifdef GL_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
bool clip_origin_lower_left = true;
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
GLenum last_clip_depth_mode = 0; glGetIntegerv(GL_CLIP_DEPTH_MODE, (GLint*)&last_clip_depth_mode);
if (last_clip_origin == GL_UPPER_LEFT) {
clip_origin_lower_left = false;
if (glClipControl)
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
}
#endif
// Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0;
#ifndef IMGUI_IMPL_OPENGL_ES2
glGenVertexArrays(1, &vertex_array_object);
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
//if (clip_origin_lower_left)
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
//else
// glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (g_GlVersion >= 3200)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else
#endif
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
}
}
// Destroy the temporary VAO
#ifndef IMGUI_IMPL_OPENGL_ES2
glDeleteVertexArrays(1, &vertex_array_object);
#endif
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
#ifdef GL_SAMPLER_BINDING
glBindSampler(0, last_sampler);
#endif
glActiveTexture(last_active_texture);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(last_vertex_array_object);
#endif
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
if (!clip_origin_lower_left && glClipControl)
glClipControl(last_clip_origin, last_clip_depth_mode);
#endif
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#ifdef GL_UNPACK_ROW_LENGTH
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
}
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
static bool CheckShader(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
static bool CheckProgram(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
GLint last_vertex_array;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#endif
// Parse GLSL version string
int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
const GLchar* vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n"
"attribute vec2 Position;\n"
"attribute vec2 UV;\n"
"attribute vec4 Color;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_130 =
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 UV;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_300_es =
"precision mediump float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_410_core =
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
//" gl_Position = ProjMtx * vec4(Position.xy,0,1) * vec4(1.0, -1.0, 1, 1);\n"
"}\n";
const GLchar* fragment_shader_glsl_120 =
"#ifdef GL_ES\n"
" precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st).r;\n"
"}\n";
const GLchar* fragment_shader_glsl_130 =
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st).r;\n"
"}\n";
const GLchar* fragment_shader_glsl_300_es =
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st).r;\n"
"}\n";
const GLchar* fragment_shader_glsl_410_core =
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"uniform sampler2D Texture;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st).r;\n"
"}\n";
#ifndef NDEBUG
printf("glsl_version: %d\n", glsl_version);
#endif
// Select shaders matching our GLSL versions
const GLchar* vertex_shader = NULL;
const GLchar* fragment_shader = NULL;
if (glsl_version < 130)
{
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
}
else if (glsl_version >= 410)
{
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
}
else if (glsl_version == 300)
{
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
}
else
{
vertex_shader = vertex_shader_glsl_130;
fragment_shader = fragment_shader_glsl_130;
}
// Create shaders
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
glCompileShader(g_VertHandle);
CheckShader(g_VertHandle, "vertex shader");
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
glCompileShader(g_FragHandle);
CheckShader(g_FragHandle, "fragment shader");
g_ShaderHandle = glCreateProgram();
glAttachShader(g_ShaderHandle, g_VertHandle);
glAttachShader(g_ShaderHandle, g_FragHandle);
glLinkProgram(g_ShaderHandle);
CheckProgram(g_ShaderHandle, "shader program");
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position");
g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV");
g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color");
// Create buffers
glGenBuffers(1, &g_VboHandle);
glGenBuffers(1, &g_ElementsHandle);
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(last_vertex_array);
#endif
return true;
}
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
#ifndef NDEBUG
printf("%s\n", __func__);
#endif
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
ImGui_ImplOpenGL3_DestroyFontsTexture();
}

@ -0,0 +1,36 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// About Desktop OpenGL function loaders:
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
// About GLSL version:
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once
// Backend API
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
// (Optional) Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();

@ -0,0 +1,361 @@
#include <iostream>
#include <array>
#include <unordered_map>
#include <cstring>
#include <cstdio>
#include <dlfcn.h>
#include <string>
#include "real_dlsym.h"
#include "loaders/loader_gl.h"
#include "GL/gl3w.h"
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "font_default.h"
#include "overlay.h"
#include "cpu.h"
#include "mesa/util/macros.h"
#include "mesa/util/os_time.h"
#include "file_utils.h"
#include <chrono>
#include <iomanip>
#define EXPORT_C_(type) extern "C" __attribute__((__visibility__("default"))) type
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName);
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName);
static gl_loader gl;
struct state {
ImGuiContext *imgui_ctx = nullptr;
ImFont* font = nullptr;
ImFont* font1 = nullptr;
};
static ImVec2 window_size;
static overlay_params params {};
static swapchain_stats sw_stats {};
static fps_limit fps_limit_stats {};
static state state;
static bool cfg_inited = false;
static bool inited = false;
static uint32_t vendorID;
static std::string deviceName;
void imgui_init()
{
if (cfg_inited)
return;
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
window_size = ImVec2(params.width, params.height);
init_system_info();
if (params.fps_limit > 0)
fps_limit_stats.targetFrameTime = int64_t(1000000000.0 / params.fps_limit);
cfg_inited = true;
}
void imgui_create(void *ctx)
{
if (inited)
return;
inited = true;
if (!ctx)
return;
cpuStats.Init();
imgui_init();
gl3wInit();
std::cerr << "GL version: " << glGetString(GL_VERSION) << std::endl;
deviceName = (char*)glGetString(GL_RENDERER);
if (deviceName.find("Radeon") != std::string::npos
|| deviceName.find("AMD") != std::string::npos){
vendorID = 0x1002;
} else {
vendorID = 0x10de;
}
init_gpu_stats(vendorID, params);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
state.imgui_ctx = ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
imgui_custom_style(params);
GLint vp [4]; glGetIntegerv (GL_VIEWPORT, vp);
ImGui::GetIO().IniFilename = NULL;
ImGui::GetIO().DisplaySize = ImVec2(vp[2], vp[3]);
ImGui_ImplOpenGL3_Init();
// Make a dummy GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
int font_size = params.font_size;
if (!font_size)
font_size = 24;
if (!params.font_file.empty() && file_exists(params.font_file)) {
state.font = io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size);
state.font1 = io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f);
} else {
ImFontConfig font_cfg = ImFontConfig();
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
const ImWchar* glyph_ranges = io.Fonts->GetGlyphRangesDefault();
state.font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, &font_cfg, glyph_ranges);
state.font1 = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55, &font_cfg, glyph_ranges);
}
sw_stats.font1 = state.font1;
engineName = "OpenGL";
}
void imgui_shutdown()
{
#ifndef NDEBUG
std::cerr << __func__ << std::endl;
#endif
if (state.imgui_ctx) {
ImGui_ImplOpenGL3_Shutdown();
ImGui::DestroyContext(state.imgui_ctx);
state.imgui_ctx = nullptr;
}
inited = false;
}
void imgui_set_context(void *ctx)
{
if (!ctx) {
imgui_shutdown();
return;
}
#ifndef NDEBUG
std::cerr << __func__ << ": " << ctx << std::endl;
#endif
imgui_create(ctx);
}
void imgui_render()
{
if (!ImGui::GetCurrentContext())
return;
GLint vp [4]; glGetIntegerv (GL_VIEWPORT, vp);
ImGui::GetIO().DisplaySize = ImVec2(vp[2], vp[3]);
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
position_layer(params, window_size, vp[2], vp[3]);
render_imgui(sw_stats, params, window_size, vp[2], vp[3]);
ImGui::PopStyleVar(3);
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
void* get_proc_address(const char* name) {
void (*func)() = (void (*)())real_dlsym( RTLD_NEXT, name );
if (!func) {
std::cerr << "MANGOHUD: Failed to get function '" << name << "'" << std::endl;
exit( 1 );
}
return (void*)func;
}
void* get_glx_proc_address(const char* name) {
if (!gl.Load()) {
// Force load libGL then. If it still doesn't find it, get_proc_address should quit the program
void *handle = dlopen("libGL.so.1", RTLD_GLOBAL | RTLD_LAZY | RTLD_DEEPBIND);
if (!handle)
std::cerr << "MANGOHUD: couldn't find libGL.so.1" << std::endl;
gl.Load();
}
void *func = nullptr;
if (gl.glXGetProcAddress)
func = gl.glXGetProcAddress( (const unsigned char*) name );
if (!func && gl.glXGetProcAddressARB)
func = gl.glXGetProcAddressARB( (const unsigned char*) name );
if (!func)
func = get_proc_address( name );
return func;
}
EXPORT_C_(void *) glXCreateContext(void *dpy, void *vis, void *shareList, int direct)
{
gl.Load();
void *ctx = gl.glXCreateContext(dpy, vis, shareList, direct);
#ifndef NDEBUG
std::cerr << __func__ << ":" << ctx << std::endl;
#endif
return ctx;
}
EXPORT_C_(bool) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
gl.Load();
#ifndef NDEBUG
std::cerr << __func__ << ": " << drawable << ", " << ctx << std::endl;
#endif
bool ret = gl.glXMakeCurrent(dpy, drawable, ctx);
if (ret)
imgui_set_context(ctx);
if (params.gl_vsync >= -1) {
if (gl.glXSwapIntervalEXT)
gl.glXSwapIntervalEXT(dpy, drawable, params.gl_vsync);
if (gl.glXSwapIntervalSGI)
gl.glXSwapIntervalSGI(params.gl_vsync);
if (gl.glXSwapIntervalMESA)
gl.glXSwapIntervalMESA(params.gl_vsync);
}
return ret;
}
EXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) {
gl.Load();
check_keybinds(params);
update_hud_info(sw_stats, params, vendorID);
imgui_render();
gl.glXSwapBuffers(dpy, drawable);
if (fps_limit_stats.targetFrameTime > 0){
fps_limit_stats.frameStart = os_time_get_nano();
FpsLimiter(fps_limit_stats);
fps_limit_stats.frameEnd = os_time_get_nano();
}
}
EXPORT_C_(void) glXSwapIntervalEXT(void *dpy, void *draw, int interval) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
gl.Load();
if (params.gl_vsync >= 0)
interval = params.gl_vsync;
gl.glXSwapIntervalEXT(dpy, draw, interval);
}
EXPORT_C_(int) glXSwapIntervalSGI(int interval) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
gl.Load();
if (params.gl_vsync >= 0)
interval = params.gl_vsync;
return gl.glXSwapIntervalSGI(interval);
}
EXPORT_C_(int) glXSwapIntervalMESA(unsigned int interval) {
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
gl.Load();
if (params.gl_vsync >= 0)
interval = (unsigned int)params.gl_vsync;
return gl.glXSwapIntervalMESA(interval);
}
EXPORT_C_(int) glXGetSwapIntervalMESA() {
gl.Load();
static bool first_call = true;
int interval = gl.glXGetSwapIntervalMESA();
if (first_call) {
first_call = false;
if (params.gl_vsync >= 0) {
interval = params.gl_vsync;
gl.glXSwapIntervalMESA(interval);
}
}
#ifndef NDEBUG
std::cerr << __func__ << ": " << interval << std::endl;
#endif
return interval;
}
struct func_ptr {
const char *name;
void *ptr;
};
static std::array<const func_ptr, 9> name_to_funcptr_map = {{
#define ADD_HOOK(fn) { #fn, (void *) fn }
ADD_HOOK(glXGetProcAddress),
ADD_HOOK(glXGetProcAddressARB),
ADD_HOOK(glXCreateContext),
ADD_HOOK(glXMakeCurrent),
ADD_HOOK(glXSwapBuffers),
ADD_HOOK(glXSwapIntervalEXT),
ADD_HOOK(glXSwapIntervalSGI),
ADD_HOOK(glXSwapIntervalMESA),
ADD_HOOK(glXGetSwapIntervalMESA),
#undef ADD_HOOK
}};
static void *find_ptr(const char *name)
{
for (auto& func : name_to_funcptr_map) {
if (strcmp(name, func.name) == 0)
return func.ptr;
}
return nullptr;
}
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
gl.Load();
//std::cerr << __func__ << ":" << procName << std::endl;
void* func = find_ptr( (const char*)procName );
if (func)
return func;
return get_glx_proc_address((const char*)procName);
}
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) {
gl.Load();
//std::cerr << __func__ << ":" << procName << std::endl;
void* func = find_ptr( (const char*)procName );
if (func)
return func;
return get_glx_proc_address((const char*)procName);
}
#ifdef HOOK_DLSYM
EXPORT_C_(void*) dlsym(void * handle, const char * name)
{
void* func = find_ptr(name);
if (func) {
//fprintf(stderr,"%s: local: %s\n", __func__ , name);
return func;
}
//fprintf(stderr,"%s: foreign: %s\n", __func__ , name);
return real_dlsym(handle, name);
}
#endif

@ -0,0 +1,18 @@
#include "real_dlsym.h"
#include <stdlib.h>
#include <dlfcn.h>
extern "C" void* __libc_dlsym( void* handle, const char* name );
void* real_dlsym( void* handle, const char* name )
{
static void *(*the_real_dlsym)( void*, const char* );
if (!the_real_dlsym) {
void* libdl = dlopen( "libdl.so", RTLD_NOW | RTLD_LOCAL );
the_real_dlsym = reinterpret_cast<decltype(the_real_dlsym)> (__libc_dlsym( libdl, "dlsym" ));
}
return the_real_dlsym( handle, name );
}

@ -0,0 +1,22 @@
/*
Copyright (C) 2016-2017 Björn Spindel
This file is part of libstrangle.
libstrangle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
libstrangle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with libstrangle. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
void* real_dlsym( void*, const char* );

@ -0,0 +1,86 @@
#include "nvidia_info.h"
#include "memory.h"
#include "gpu.h"
struct gpuInfo gpu_info;
FILE *amdGpuFile = nullptr, *amdTempFile = nullptr, *amdGpuVramTotalFile = nullptr, *amdGpuVramUsedFile = nullptr, *amdGpuCoreClockFile = nullptr, *amdGpuMemoryClockFile = nullptr;
pthread_t cpuThread, gpuThread, cpuInfoThread;
void *getNvidiaGpuInfo(void *){
if (!nvmlSuccess)
checkNvidia();
if (nvmlSuccess){
getNvidiaInfo();
gpu_info.load = nvidiaUtilization.gpu;
gpu_info.temp = nvidiaTemp;
gpu_info.memoryUsed = nvidiaMemory.used / (1024.f * 1024.f * 1024.f);
gpu_info.CoreClock = nvidiaCoreClock;
gpu_info.MemClock = nvidiaMemClock * 2;
}
pthread_detach(gpuThread);
return NULL;
}
void *getAmdGpuUsage(void *){
int64_t value = 0;
if (amdGpuFile) {
rewind(amdGpuFile);
fflush(amdGpuFile);
if (fscanf(amdGpuFile, "%d", &amdgpu.load) != 1)
amdgpu.load = 0;
gpu_info.load = amdgpu.load;
}
if (amdTempFile) {
rewind(amdTempFile);
fflush(amdTempFile);
if (fscanf(amdTempFile, "%d", &amdgpu.temp) != 1)
amdgpu.temp = 0;
amdgpu.temp /= 1000;
gpu_info.temp = amdgpu.temp;
}
if (amdGpuVramTotalFile) {
rewind(amdGpuVramTotalFile);
fflush(amdGpuVramTotalFile);
if (fscanf(amdGpuVramTotalFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.memoryTotal = float(value) / (1024 * 1024 * 1024);
gpu_info.memoryTotal = amdgpu.memoryTotal;
}
if (amdGpuVramUsedFile) {
rewind(amdGpuVramUsedFile);
fflush(amdGpuVramUsedFile);
if (fscanf(amdGpuVramUsedFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.memoryUsed = float(value) / (1024 * 1024 * 1024);
gpu_info.memoryUsed = amdgpu.memoryUsed;
}
if (amdGpuCoreClockFile) {
rewind(amdGpuCoreClockFile);
fflush(amdGpuCoreClockFile);
if (fscanf(amdGpuCoreClockFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.CoreClock = value / 1000000;
gpu_info.CoreClock = amdgpu.CoreClock;
}
if (amdGpuMemoryClockFile) {
rewind(amdGpuMemoryClockFile);
fflush(amdGpuMemoryClockFile);
if (fscanf(amdGpuMemoryClockFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.MemClock = value / 1000000;
gpu_info.MemClock = amdgpu.MemClock;
}
pthread_detach(gpuThread);
return NULL;
}

@ -0,0 +1,34 @@
#include <thread>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "nvidia_info.h"
using namespace std;
extern FILE *amdGpuFile, *amdTempFile, *amdGpuVramTotalFile, *amdGpuVramUsedFile, *amdGpuCoreClockFile, *amdGpuMemoryClockFile;
extern pthread_t cpuThread, gpuThread, cpuInfoThread;
struct amdGpu {
int load;
int temp;
float memoryUsed;
float memoryTotal;
int MemClock;
int CoreClock;
};
struct gpuInfo{
int load;
int temp;
float memoryUsed;
float memoryTotal;
int MemClock;
int CoreClock;
};
extern struct amdGpu amdgpu;
extern struct gpuInfo gpu_info;
void *getNvidiaInfo(void*);
void *getNvidiaGpuInfo(void*);
void *getAmdGpuUsage(void*);

@ -0,0 +1,27 @@
#include "iostats.h"
#include "string_utils.h"
#include <fstream>
pthread_t ioThread;
void *getIoStats(void *args) {
iostats *io = reinterpret_cast<iostats *>(args);
if (io) {
io->prev.read_bytes = io->curr.read_bytes;
io->prev.write_bytes = io->curr.write_bytes;
std::string line;
std::ifstream f("/proc/self/io");
while (std::getline(f, line)) {
if (starts_with(line, "read_bytes:")) {
try_stoull(io->curr.read_bytes, line.substr(12));
}
else if (starts_with(line, "write_bytes:")) {
try_stoull(io->curr.write_bytes, line.substr(13));
}
}
io->diff.read = (io->curr.read_bytes - io->prev.read_bytes) / (1024.f * 1024.f);
io->diff.write = (io->curr.write_bytes - io->prev.write_bytes) / (1024.f * 1024.f);
}
pthread_detach(ioThread);
return NULL;
}

@ -0,0 +1,22 @@
#pragma once
#include <pthread.h>
#include <inttypes.h>
extern pthread_t ioThread;
struct iostats {
struct {
unsigned long long read_bytes;
unsigned long long write_bytes;
} curr;
struct {
unsigned long long read_bytes;
unsigned long long write_bytes;
} prev;
struct {
float read;
float write;
} diff;
};
void *getIoStats(void *args);

@ -3,8 +3,8 @@
#include "X11/keysym.h"
#include "mesa/util/os_time.h"
double elapsedF2, elapsedF12, elapsedRefreshConfig;
uint64_t last_f2_press, last_f12_press, refresh_config_press;
double elapsedF2, elapsedF12, elapsedReloadCfg;
uint64_t last_f2_press, last_f12_press, reload_cfg_press;
pthread_t f2;
char *displayid = getenv("DISPLAY");
Display *dpy = XOpenDisplay(displayid);

@ -0,0 +1,102 @@
#include "gl/real_dlsym.h"
#include "loaders/loader_gl.h"
gl_loader::gl_loader() : loaded_(false) {
}
gl_loader::~gl_loader() {
CleanUp(loaded_);
}
bool gl_loader::Load(bool egl_only) {
if (loaded_) {
return true;
}
eglSwapBuffers =
reinterpret_cast<decltype(this->eglSwapBuffers)>(
real_dlsym(RTLD_NEXT, "eglSwapBuffers"));
if (egl_only) {
loaded_ = true;
return true;
}
glXGetProcAddress =
reinterpret_cast<decltype(this->glXGetProcAddress)>(
real_dlsym(RTLD_NEXT, "glXGetProcAddress"));
glXGetProcAddressARB =
reinterpret_cast<decltype(this->glXGetProcAddressARB)>(
real_dlsym(RTLD_NEXT, "glXGetProcAddressARB"));
if (!glXGetProcAddress) {
CleanUp(true);
return false;
}
glXCreateContext =
reinterpret_cast<decltype(this->glXCreateContext)>(
glXGetProcAddress((const unsigned char *)"glXCreateContext"));
if (!glXCreateContext) {
CleanUp(true);
return false;
}
glXDestroyContext =
reinterpret_cast<decltype(this->glXDestroyContext)>(
glXGetProcAddress((const unsigned char *)"glXDestroyContext"));
if (!glXDestroyContext) {
CleanUp(true);
return false;
}
glXSwapBuffers =
reinterpret_cast<decltype(this->glXSwapBuffers)>(
glXGetProcAddress((const unsigned char *)"glXSwapBuffers"));
if (!glXSwapBuffers) {
CleanUp(true);
return false;
}
glXSwapIntervalEXT =
reinterpret_cast<decltype(this->glXSwapIntervalEXT)>(
glXGetProcAddress((const unsigned char *)"glXSwapIntervalEXT"));
glXSwapIntervalSGI =
reinterpret_cast<decltype(this->glXSwapIntervalSGI)>(
glXGetProcAddress((const unsigned char *)"glXSwapIntervalSGI"));
glXSwapIntervalMESA =
reinterpret_cast<decltype(this->glXSwapIntervalMESA)>(
glXGetProcAddress((const unsigned char *)"glXSwapIntervalMESA"));
glXGetSwapIntervalMESA =
reinterpret_cast<decltype(this->glXGetSwapIntervalMESA)>(
glXGetProcAddress((const unsigned char *)"glXGetSwapIntervalMESA"));
glXMakeCurrent =
reinterpret_cast<decltype(this->glXMakeCurrent)>(
glXGetProcAddress((const unsigned char *)"glXMakeCurrent"));
if (!glXMakeCurrent) {
CleanUp(true);
return false;
}
loaded_ = true;
return true;
}
void gl_loader::CleanUp(bool unload) {
loaded_ = false;
glXGetProcAddress = nullptr;
glXGetProcAddressARB = nullptr;
glXCreateContext = nullptr;
glXDestroyContext = nullptr;
glXSwapBuffers = nullptr;
glXSwapIntervalEXT = nullptr;
glXSwapIntervalSGI = nullptr;
glXSwapIntervalMESA = nullptr;
glXMakeCurrent = nullptr;
}

@ -0,0 +1,38 @@
#ifndef LIBRARY_LOADER_GL_H
#define LIBRARY_LOADER_GL_H
#include "gl/gl.h"
#include <dlfcn.h>
class gl_loader {
public:
gl_loader();
~gl_loader();
bool Load(bool egl_only = false);
bool IsLoaded() { return loaded_; }
decltype(&::glXGetProcAddress) glXGetProcAddress;
decltype(&::glXGetProcAddressARB) glXGetProcAddressARB;
decltype(&::glXCreateContext) glXCreateContext;
decltype(&::glXDestroyContext) glXDestroyContext;
decltype(&::glXSwapBuffers) glXSwapBuffers;
decltype(&::glXSwapIntervalEXT) glXSwapIntervalEXT;
decltype(&::glXSwapIntervalSGI) glXSwapIntervalSGI;
decltype(&::glXSwapIntervalMESA) glXSwapIntervalMESA;
decltype(&::glXGetSwapIntervalMESA) glXGetSwapIntervalMESA;
decltype(&::glXMakeCurrent) glXMakeCurrent;
decltype(&::eglSwapBuffers) eglSwapBuffers;
private:
void CleanUp(bool unload);
bool loaded_;
// Disallow copy constructor and assignment operator.
gl_loader(const gl_loader&);
void operator=(const gl_loader&);
};
#endif // LIBRARY_LOADER_GL_H

@ -135,7 +135,7 @@ bool libnvml_loader::Load(const std::string& library_name) {
return false;
}
#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)
#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)
nvmlDeviceGetMemoryInfo =
reinterpret_cast<decltype(this->nvmlDeviceGetMemoryInfo)>(
dlsym(library_, "nvmlDeviceGetMemoryInfo"));
@ -148,6 +148,19 @@ bool libnvml_loader::Load(const std::string& library_name) {
return false;
}
#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)
nvmlDeviceGetClockInfo =
reinterpret_cast<decltype(this->nvmlDeviceGetClockInfo)>(
dlsym(library_, "nvmlDeviceGetClockInfo"));
#endif
#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)
nvmlDeviceGetClockInfo = &::nvmlDeviceGetClockInfo;
#endif
if (!nvmlDeviceGetClockInfo) {
CleanUp(true);
return false;
}
loaded_ = true;
return true;
}

@ -30,6 +30,7 @@ class libnvml_loader {
decltype(&::nvmlDeviceGetHandleByIndex_v2) nvmlDeviceGetHandleByIndex_v2;
decltype(&::nvmlDeviceGetHandleByPciBusId_v2) nvmlDeviceGetHandleByPciBusId_v2;
decltype(&::nvmlDeviceGetMemoryInfo) nvmlDeviceGetMemoryInfo;
decltype(&::nvmlDeviceGetClockInfo) nvmlDeviceGetClockInfo;
private:
void CleanUp(bool unload);

@ -22,10 +22,8 @@ struct logData{
double fps, elapsedLog;
std::vector<logData> logArray;
ofstream out;
const char* log_duration_env = std::getenv("LOG_DURATION");
const char* mangohud_output_env = std::getenv("MANGOHUD_OUTPUT");
const char* log_period_env = std::getenv("LOG_PERIOD");
int duration, num;
int num;
bool loggingOn;
uint64_t log_start;
@ -39,12 +37,13 @@ uint64_t log_start;
// logArray.clear();
// }
void *logging(void *){
void *logging(void *params_void){
overlay_params *params = reinterpret_cast<overlay_params *>(params_void);
time_t now_log = time(0);
tm *log_time = localtime(&now_log);
string date = to_string(log_time->tm_year + 1900) + "-" + to_string(1 + log_time->tm_mon) + "-" + to_string(log_time->tm_mday) + "_" + to_string(1 + log_time->tm_hour) + "-" + to_string(1 + log_time->tm_min) + "-" + to_string(1 + log_time->tm_sec);
log_start = os_time_get();
out.open(mangohud_output_env + date, ios::out | ios::app);
out.open(params->output_file + date, ios::out | ios::app);
out << "os," << "cpu," << "gpu," << "ram," << "kernel," << "driver" << endl;
out << os << "," << cpu << "," << gpu << "," << ram << "," << kernel << "," << driver << endl;
while (loggingOn){
@ -53,7 +52,7 @@ void *logging(void *){
out << fps << "," << cpuLoadLog << "," << gpuLoadLog << "," << now - log_start << endl;
// logArray.push_back({fps, cpuLoadLog, gpuLoadLog, 0.0f});
if ((elapsedLog) >= duration * 1000000 && log_duration_env)
if ((elapsedLog) >= params->log_duration * 1000000 && params->log_duration)
loggingOn = false;
this_thread::sleep_for(chrono::milliseconds(log_period));

@ -1,12 +1,16 @@
{
"file_format_version" : "1.0.0",
"layer" : {
"name": "MangoHud 64bit",
"name": "MangoHud",
"type": "GLOBAL",
"api_version": "1.1.125",
"library_path": "libMangoHud.so",
"implementation_version": "1",
"description": "Vulkan Hud Overlay",
"functions": {
"vkGetInstanceProcAddr": "overlay_GetInstanceProcAddr",
"vkGetDeviceProcAddr": "overlay_GetDeviceProcAddr"
},
"enable_environment": {
"MANGOHUD": "1"
},

@ -0,0 +1,22 @@
{
"file_format_version" : "1.0.0",
"layer" : {
"name": "@PROJECT_NAME@@LAYER_SUFFIX@",
"type": "GLOBAL",
"api_version": "1.1.125",
"library_path": "@libdir_mangohud@libMangoHud.so",
"implementation_version": "1",
"description": "Vulkan Hud Overlay",
"functions": {
"vkGetInstanceProcAddr": "overlay_GetInstanceProcAddr",
"vkGetDeviceProcAddr": "overlay_GetDeviceProcAddr"
},
"enable_environment": {
"MANGOHUD": "1"
},
"disable_environment": {
"DISABLE_MANGOHUD": "1"
}
}
}

@ -41,14 +41,27 @@ vklayer_files = files(
'file_utils.cpp',
'memory.cpp',
'config.cpp',
'iostats.cpp',
'gpu.cpp',
)
opengl_files = files(
'gl/inject.cpp',
'gl/real_dlsym.cpp',
'gl/imgui_impl_opengl3.cpp',
'loaders/loader_gl.cpp',
'gl/gl3w/GL/gl3w.c',
)
pre_args += '-DHOOK_DLSYM'
inc_opengl = include_directories('gl/gl3w')
# lib_xnvctrl = cc.find_library('XNVCtrl')
vklayer_mesa_overlay = shared_library(
'MangoHud',
util_files,
vk_enum_to_str,
vklayer_files,
opengl_files,
overlay_spv,
vulkan_headers,
c_args : [
@ -68,12 +81,41 @@ vklayer_mesa_overlay = shared_library(
dep_dl,
dep_pthread,
dep_vulkan],
include_directories : inc_common,
include_directories : [inc_common, inc_opengl],
link_args : cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro']),
install_dir : libdir_mangohud,
install : true
)
install_data(
files('mangohud.json'),
if get_option('using_build_sh')
configure_file(input : 'mangohud.json.in',
output : '@0@.json'.format(meson.project_name()),
configuration : {'PROJECT_NAME' : meson.project_name(),
'libdir_mangohud' : '',
'LAYER_SUFFIX' : ''},
install : true,
install_dir : join_paths(get_option('datadir'), 'vulkan', 'implicit_layer.d'),
)
else
configure_file(input : 'mangohud.json.in',
output : '@0@.@1@.json'.format(meson.project_name(), target_machine.cpu_family()),
configuration : {'libdir_mangohud' : join_paths(get_option('prefix'), get_option('libdir'), 'mangohud') + '/',
'PROJECT_NAME' : meson.project_name() + ' ',
'LAYER_SUFFIX' : target_machine.cpu_family()},
install : true,
install_dir : join_paths(get_option('datadir'), 'vulkan', 'implicit_layer.d'),
)
endif
install_data(
files('../bin/run-mangohud-gl-pkg.sh'),
install_dir : get_option('bindir'),
install_mode: 'rwxr-xr-x',
rename : ['mangohud']
)
install_data(
files('../bin/MangoHud.conf'),
install_dir : join_paths(get_option('datadir'), 'doc', 'mangohud'),
rename : ['MangoHud.conf.example']
)

@ -3,8 +3,7 @@
#include <nvml.h>
extern nvmlReturn_t result;
extern unsigned int nvidiaTemp, processSamplesCount, lastSeenTimeStamp, *vgpuInstanceSamplesCount;
extern nvmlValueType_t *sampleValType;
extern unsigned int nvidiaTemp, processSamplesCount, *vgpuInstanceSamplesCount, nvidiaCoreClock, nvidiaMemClock;
extern nvmlDevice_t nvidiaDevice;
extern struct nvmlUtilization_st nvidiaUtilization;
extern struct nvmlMemory_st nvidiaMemory;

@ -6,7 +6,7 @@ libnvml_loader nvml("libnvidia-ml.so.1");
nvmlReturn_t result;
nvmlDevice_t nvidiaDevice;
bool nvmlSuccess = false;
unsigned int nvidiaTemp;
unsigned int nvidiaTemp, nvidiaCoreClock, nvidiaMemClock;
struct nvmlUtilization_st nvidiaUtilization;
struct nvmlMemory_st nvidiaMemory {};
@ -30,4 +30,6 @@ void getNvidiaInfo(){
nvml.nvmlDeviceGetUtilizationRates(nvidiaDevice, &nvidiaUtilization);
nvml.nvmlDeviceGetTemperature(nvidiaDevice, NVML_TEMPERATURE_GPU, &nvidiaTemp);
nvml.nvmlDeviceGetMemoryInfo(nvidiaDevice, &nvidiaMemory);
nvml.nvmlDeviceGetClockInfo(nvidiaDevice, NVML_CLOCK_GRAPHICS, &nvidiaCoreClock);
nvml.nvmlDeviceGetClockInfo(nvidiaDevice, NVML_CLOCK_MEM, &nvidiaMemClock);
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,44 @@
#include <string>
#include <stdint.h>
#include "imgui.h"
#include "overlay_params.h"
#include "iostats.h"
extern std::string engineName;
struct frame_stat {
uint64_t stats[OVERLAY_PARAM_ENABLED_MAX];
};
struct swapchain_stats {
uint64_t n_frames;
enum overlay_param_enabled stat_selector;
double time_dividor;
struct frame_stat stats_min, stats_max;
struct frame_stat frames_stats[200];
ImFont* font1 = nullptr;
std::string time;
double fps;
struct iostats io;
int total_cpu;
uint64_t last_present_time;
unsigned n_frames_since_update;
uint64_t last_fps_update;
};
struct fps_limit {
int64_t frameStart;
int64_t frameEnd;
int64_t targetFrameTime;
int64_t frameOverhead;
int64_t sleepTime;
};
void position_layer(struct overlay_params& params, ImVec2 window_size, unsigned width, unsigned height);
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, unsigned width, unsigned height);
void update_hud_info(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID);
void init_gpu_stats(uint32_t& vendorID, overlay_params& params);
void check_keybinds(struct overlay_params& params);
void init_system_info(void);
void FpsLimiter(struct fps_limit& stats);
void imgui_custom_style(struct overlay_params& params);

@ -24,11 +24,11 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fstream>
#include <errno.h>
#include <sys/sysinfo.h>
#include <X11/Xlib.h>
#include "X11/keysym.h"
#include "imgui.h"
#include "overlay_params.h"
#include "config.h"
@ -49,12 +49,6 @@ parse_position(const char *str)
return LAYER_POSITION_TOP_LEFT;
}
static FILE *
parse_output_file(const char *str)
{
return fopen(str, "w+");
}
static int
parse_control(const char *str)
{
@ -82,6 +76,12 @@ parse_background_alpha(const char *str)
return strtof(str, NULL);
}
static float
parse_alpha(const char *str)
{
return strtof(str, NULL);
}
static KeySym
parse_toggle_hud(const char *str)
{
@ -95,7 +95,7 @@ parse_toggle_logging(const char *str)
}
static KeySym
parse_refresh_config(const char *str)
parse_reload_cfg(const char *str)
{
return XStringToKeysym(str);
}
@ -136,13 +136,41 @@ parse_unsigned(const char *str)
return strtol(str, NULL, 0);
}
static signed
parse_signed(const char *str)
{
return strtol(str, NULL, 0);
}
static const char *
parse_str(const char *str)
{
return str;
}
#define parse_width(s) parse_unsigned(s)
#define parse_height(s) parse_unsigned(s)
#define parse_vsync(s) parse_unsigned(s)
#define parse_gl_vsync(s) parse_signed(s)
#define parse_offset_x(s) parse_unsigned(s)
#define parse_offset_y(s) parse_unsigned(s)
#define parse_log_duration(s) parse_unsigned(s)
#define parse_time_format(s) parse_str(s)
#define parse_output_file(s) parse_str(s)
#define parse_font_file(s) parse_str(s)
#define parse_io_read(s) parse_unsigned(s)
#define parse_io_write(s) parse_unsigned(s)
#define parse_crosshair_color(s) parse_color(s)
#define parse_cpu_color(s) parse_color(s)
#define parse_gpu_color(s) parse_color(s)
#define parse_vram_color(s) parse_color(s)
#define parse_ram_color(s) parse_color(s)
#define parse_engine_color(s) parse_color(s)
#define parse_io_color(s) parse_color(s)
#define parse_frametime_color(s) parse_color(s)
#define parse_background_color(s) parse_color(s)
#define parse_text_color(s) parse_color(s)
static bool
parse_help(const char *str)
@ -182,8 +210,15 @@ parse_string(const char *s, char *out_param, char *out_value)
if (*s == '=') {
s++;
i++;
for (; !is_delimiter(*s); s++, out_value++, i++)
for (; !is_delimiter(*s); s++, out_value++, i++) {
*out_value = *s;
// Consume escaped delimiter, but don't escape null. Might be end of string.
if (*s == '\\' && *(s + 1) != 0 && is_delimiter(*(s + 1))) {
s++;
i++;
*out_value = *s;
}
}
} else
*(out_value++) = '1';
*out_value = 0;
@ -252,7 +287,7 @@ parse_overlay_config(struct overlay_params *params,
const char *env)
{
memset(params, 0, sizeof(*params));
*params = {};
/* Visible by default */
params->enabled[OVERLAY_PARAM_ENABLED_fps] = true;
@ -265,19 +300,33 @@ parse_overlay_config(struct overlay_params *params,
params->enabled[OVERLAY_PARAM_ENABLED_ram] = false;
params->enabled[OVERLAY_PARAM_ENABLED_vram] = false;
params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = false;
params->enabled[OVERLAY_PARAM_ENABLED_io_read] = false;
params->enabled[OVERLAY_PARAM_ENABLED_io_write] = false;
params->fps_sampling_period = 500000; /* 500ms */
params->width = 280;
params->height = 140;
params->control = -1;
params->toggle_hud = XK_F12;
params->toggle_logging = XK_F2;
params->refresh_config = XK_F4;
params->reload_cfg = XK_F4;
params->fps_limit = 0;
params->vsync = -1;
params->gl_vsync = -2;
params->crosshair_size = 30;
params->offset_x = 0;
params->offset_y = 0;
params->background_alpha = 0.5;
params->alpha = 1.0;
params->time_format = "%T";
params->gpu_color = strtol("2e9762", NULL, 16);
params->cpu_color = strtol("2e97cb", NULL, 16);
params->vram_color = strtol("ad64c1", NULL, 16);
params->ram_color = strtol("c26693", NULL, 16);
params->engine_color = strtol("eb5b5b", NULL, 16);
params->io_color = strtol("a491d3", NULL, 16);
params->frametime_color = strtol("00ff00", NULL, 16);
params->background_color = strtol("020202", NULL, 16);
params->text_color = strtol("ffffff", NULL, 16);
// first pass with env var
if (env)
@ -325,4 +374,42 @@ parse_overlay_config(struct overlay_params *params,
// Command buffer gets reused and timestamps cause hangs for some reason, force off for now
params->enabled[OVERLAY_PARAM_ENABLED_gpu_timing] = false;
// Convert from 0xRRGGBB to ImGui's format
std::array<unsigned *, 10> colors = {
&params->crosshair_color,
&params->cpu_color,
&params->gpu_color,
&params->vram_color,
&params->ram_color,
&params->engine_color,
&params->io_color,
&params->background_color,
&params->frametime_color,
&params->text_color,
};
for (auto color : colors){
*color =
IM_COL32(RGBGetRValue(*color),
RGBGetGValue(*color),
RGBGetBValue(*color),
255);
}
params->tableCols = 3;
if (!params->font_size) {
params->font_size = 24;
} else {
params->width = params->font_size * 11.7;
}
//increase hud width if io read and write
if (params->enabled[OVERLAY_PARAM_ENABLED_io_read] && params->enabled[OVERLAY_PARAM_ENABLED_io_write] && params->width == 280)
params->width = 15 * params->font_size;
if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock] && params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] && params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats]){
params->tableCols = 4;
params->width = 20 * params->font_size;
}
}

@ -24,6 +24,8 @@
#ifndef OVERLAY_PARAMS_H
#define OVERLAY_PARAMS_H
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
@ -33,6 +35,12 @@ extern "C" {
#include <stdbool.h>
#include <X11/Xlib.h>
#define RGBGetBValue(rgb) (rgb & 0x000000FF)
#define RGBGetGValue(rgb) ((rgb >> 8) & 0x000000FF)
#define RGBGetRValue(rgb) ((rgb >> 16) & 0x000000FF)
#define ToRGBColor(r, g, b, a) ((r << 16) | (g << 8) | (b));
#define OVERLAY_PARAMS \
OVERLAY_PARAM_BOOL(fps) \
OVERLAY_PARAM_BOOL(frame) \
@ -50,8 +58,13 @@ extern "C" {
OVERLAY_PARAM_BOOL(time) \
OVERLAY_PARAM_BOOL(full) \
OVERLAY_PARAM_BOOL(read_cfg) \
OVERLAY_PARAM_BOOL(io_read) \
OVERLAY_PARAM_BOOL(io_write) \
OVERLAY_PARAM_BOOL(gpu_mem_clock) \
OVERLAY_PARAM_BOOL(gpu_core_clock) \
OVERLAY_PARAM_CUSTOM(fps_sampling_period) \
OVERLAY_PARAM_CUSTOM(output_file) \
OVERLAY_PARAM_CUSTOM(font_file) \
OVERLAY_PARAM_CUSTOM(position) \
OVERLAY_PARAM_CUSTOM(width) \
OVERLAY_PARAM_CUSTOM(height) \
@ -59,15 +72,30 @@ extern "C" {
OVERLAY_PARAM_CUSTOM(control) \
OVERLAY_PARAM_CUSTOM(fps_limit) \
OVERLAY_PARAM_CUSTOM(vsync) \
OVERLAY_PARAM_CUSTOM(gl_vsync) \
OVERLAY_PARAM_CUSTOM(font_size) \
OVERLAY_PARAM_CUSTOM(toggle_hud) \
OVERLAY_PARAM_CUSTOM(toggle_logging) \
OVERLAY_PARAM_CUSTOM(refresh_config) \
OVERLAY_PARAM_CUSTOM(reload_cfg) \
OVERLAY_PARAM_CUSTOM(crosshair_size) \
OVERLAY_PARAM_CUSTOM(offset_x) \
OVERLAY_PARAM_CUSTOM(offset_y) \
OVERLAY_PARAM_CUSTOM(crosshair_color) \
OVERLAY_PARAM_CUSTOM(background_alpha) \
OVERLAY_PARAM_CUSTOM(time_format) \
OVERLAY_PARAM_CUSTOM(io_read) \
OVERLAY_PARAM_CUSTOM(io_write) \
OVERLAY_PARAM_CUSTOM(cpu_color) \
OVERLAY_PARAM_CUSTOM(gpu_color) \
OVERLAY_PARAM_CUSTOM(vram_color) \
OVERLAY_PARAM_CUSTOM(ram_color) \
OVERLAY_PARAM_CUSTOM(engine_color) \
OVERLAY_PARAM_CUSTOM(frametime_color) \
OVERLAY_PARAM_CUSTOM(background_color) \
OVERLAY_PARAM_CUSTOM(io_color) \
OVERLAY_PARAM_CUSTOM(text_color) \
OVERLAY_PARAM_CUSTOM(alpha) \
OVERLAY_PARAM_CUSTOM(log_duration) \
OVERLAY_PARAM_CUSTOM(help)
enum overlay_param_position {
@ -89,7 +117,6 @@ enum overlay_param_enabled {
struct overlay_params {
bool enabled[OVERLAY_PARAM_ENABLED_MAX];
enum overlay_param_position position;
FILE *output_file;
int control;
uint32_t fps_sampling_period; /* us */
uint32_t fps_limit;
@ -97,17 +124,21 @@ struct overlay_params {
bool help;
bool no_display;
bool full;
bool io_read, io_write;
unsigned width;
unsigned height;
unsigned offset_x;
unsigned offset_y;
int offset_x, offset_y;
unsigned vsync;
unsigned crosshair_color;
int gl_vsync;
int log_duration;
unsigned crosshair_color, cpu_color, gpu_color, vram_color, ram_color, engine_color, io_color, frametime_color, background_color, text_color;
unsigned tableCols;
float font_size;
float background_alpha;
float background_alpha, alpha;
KeySym toggle_hud;
KeySym toggle_logging;
KeySym refresh_config;
KeySym reload_cfg;
std::string time_format, output_file, font_file;
};
const extern char *overlay_param_names[];

@ -73,4 +73,15 @@ static bool try_stoi(int& val, const std::string& str, std::size_t* pos = 0, int
return false;
}
static bool try_stoull(unsigned long long& val, const std::string& str, std::size_t* pos = 0, int base = 10)
{
try {
val = std::stoull(str, pos, base);
return true;
} catch (std::invalid_argument& e) {
std::cerr << __func__ << ": invalid argument: '" << str << "'" << std::endl;
}
return false;
}
#pragma GCC diagnostic pop

Loading…
Cancel
Save