Merge branch 'develop' into benchmark-percentages

pull/236/head
flightlessmango 4 years ago committed by GitHub
commit eafa62356b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -135,6 +135,11 @@ A partial list of parameters are below. See the config file for a complete list.
| `ram`<br>`vram` | Displays system RAM/VRAM usage |
| `full` | Enables all of the above config options |
| `font_size=` | Customizeable font size (default=24) |
| `font_size_text=` | Customizeable font size for other text like media metadata (default=24) |
| `font_scale=` | Set global font scale (default=1.0) |
| `font_file` | Change default font (set location to .TTF/.OTF file ) |
| `font_file_text` | Change text font. Otherwise `font_file` is used |
| `font_glyph_ranges` | Specify extra font glyph ranges, comma separated: `korean`, `chinese`, `chinese_simplified`, `japanese`, `cyrillic`, `thai`, `vietnamese`, `latin_ext_a`, `latin_ext_b`. If you experience crashes or text is just squares, reduce font size or glyph ranges. |
| `width=`<br>`height=` | Customizeable hud dimensions (in pixels) |
| `position=` | Location of the hud: `top-left` (default), `top-right`, `bottom-left`, `bottom-right`, `top-center` |
| `offset_x` `offset_y` | Hud position offsets |
@ -147,7 +152,6 @@ A partial list of parameters are below. See the config file for a complete list.
| `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 |
| `media_player` | Show media player metadata |

@ -48,8 +48,22 @@ frame_timing
### Change the hud font size (default is 24)
font_size=24
# font_scale=1.0
# font_size_text=24
# font_scale_media_player = 0.55
### Change default font (set location to .TTF/.OTF file )
## Set font for the whole hud
# font_file=
## Set font only for text like media player metadata
# font_file_text=
## Set font glyph ranges. Defaults to latin-only. Don't forget to set font_file/text_font_file to font that supports these.
## Probably don't enable all at once because of memory usage and hardware limits concerns.
## If you experience crashes or text is just squares, reduce glyph range or reduce font size.
# font_glyph_ranges=korean, chinese, chinese_simplified, japanese, cyrillic, thai, vietnamese, latin_ext_a, latin_ext_b
### Change the hud position (default is top-left)
position=top-left
@ -91,9 +105,6 @@ background_alpha=0.5
# background_color=020202
# media_player_color=FFFFFF
### Change default font (set location to .TTF/.OTF file )
# font_file
### Show media player metadata
# media_player
# media_player_name = spotify
@ -121,4 +132,4 @@ background_alpha=0.5
# permit_upload=1
### Define a '+'-separated list of percentiles shown in the benchmark results.
### Use "AVG" to get a mean average. Default percentiles are 97+AVG+1+0.1
# benchmark_percentiles=
# benchmark_percentiles=

@ -0,0 +1,185 @@
#!/usr/bin/env bash
set -e
# Specialized build script for Steam Runtime SDK docker
OS_RELEASE_FILES=("/etc/os-release" "/usr/lib/os-release")
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
DATA_DIR="$XDG_DATA_HOME/MangoHud"
CONFIG_DIR="$XDG_CONFIG_HOME/MangoHud"
LAYER="build/release/usr/share/vulkan/implicit_layer.d/mangohud.json"
INSTALL_DIR="build/package/"
IMPLICIT_LAYER_DIR="$XDG_DATA_HOME/vulkan/implicit_layer.d"
VERSION=$(git describe --long --tags --always | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//')
dependencies() {
if [[ ! -f build/release/usr/lib64/libMangoHud.so ]]; then
install() {
set +e
for i in $(eval echo $DEPS); do
dpkg-query -s "$i" &> /dev/null
if [[ $? == 1 ]]; then
INSTALL="$INSTALL""$i "
fi
done
if [[ ! -z "$INSTALL" ]]; then
apt-get update
apt-get -y install $INSTALL
fi
set -e
}
echo "# Checking Dependencies"
DEPS="{gcc-5-multilib,g++-5-multilib,unzip}"
install
# py3.2 is weird
ln -sf python3.5 /usr/bin/python3
if [[ ! -f ./bin/get-pip.py ]]; then
curl https://bootstrap.pypa.io/get-pip.py -o bin/get-pip.py
python3.5 ./bin/get-pip.py
fi
if [[ $(pip3.5 show meson; echo $?) == 1 || $(pip3.5 show mako; echo $?) == 1 ]]; then
pip3.5 install meson mako
fi
if [[ ! -f /usr/include/NVCtrl/NVCtrl.h ]]; then
curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl0_440.64-0ubuntu1_amd64.deb
curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl-dev_440.64-0ubuntu1_amd64.deb
dpkg -i libxnvctrl0_440.64-0ubuntu1_amd64.deb libxnvctrl-dev_440.64-0ubuntu1_amd64.deb
fi
# preinstalled 7.10.xxxx
#if [[ ! -f /usr/local/bin/glslangValidator ]]; then
# curl -LO https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip
# unzip glslang-master-linux-Release.zip bin/glslangValidator
# /usr/bin/install -m755 bin/glslangValidator /usr/local/bin/
# rm bin/glslangValidator glslang-master-linux-Release.zip
#fi
fi
}
configure() {
dependencies
git submodule update --init
if [[ ! -f "build/meson64/build.ninja" ]]; then
export CC="gcc-5"
export CXX="g++-5"
meson build/meson64 --libdir lib/mangohud/lib64 --prefix /usr -Dappend_libdir_mangohud=false ${CONFIGURE_OPTS}
fi
if [[ ! -f "build/meson32/build.ninja" ]]; then
export CC="gcc-5 -m32"
export CXX="g++-5 -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 lib/mangohud/lib32 --prefix /usr -Dappend_libdir_mangohud=false ${CONFIGURE_OPTS}
fi
}
build() {
if [[ ! -f "build/meson64/build.ninja" || ! -f "build/meson32/build.ninja" ]]; then
configure
fi
DESTDIR="$PWD/build/release" ninja -C build/meson32 install
DESTDIR="$PWD/build/release" ninja -C build/meson64 install
}
package() {
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
tar --numeric-owner --owner=0 --group=0 \
-C build/release -cvf "build/MangoHud-package.tar" .
}
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() {
rm -rf "$HOME/.local/share/MangoHud/"
rm -f "$HOME/.local/share/vulkan/implicit_layer.d/"{mangohud32.json,mangohud64.json}
[ "$UID" -eq 0 ] || mkdir -pv "${CONFIG_DIR}"
[ "$UID" -eq 0 ] || exec sudo bash "$0" install
/usr/bin/install -vm644 -D ./build/release/usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so
/usr/bin/install -vm644 -D ./build/release/usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so
/usr/bin/install -vm644 -D ./build/release/usr/lib/mangohud/lib32/libMangoHud_dlsym.so /usr/lib/mangohud/lib32/libMangoHud_dlsym.so
/usr/bin/install -vm644 -D ./build/release/usr/lib/mangohud/lib64/libMangoHud_dlsym.so /usr/lib/mangohud/lib64/libMangoHud_dlsym.so
/usr/bin/install -vm644 -D ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86.json
/usr/bin/install -vm644 -D ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json
/usr/bin/install -vm644 -D ./build/release/usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example
/usr/bin/install -vm755 ./build/release/usr/bin/mangohud.x86 /usr/bin/mangohud.x86
/usr/bin/install -vm755 ./build/release/usr/bin/mangohud /usr/bin/mangohud
echo "MangoHud Installed"
}
clean() {
rm -rf "build"
}
uninstall() {
[ "$UID" -eq 0 ] || exec sudo bash "$0" uninstall
rm -rfv "/usr/lib/mangohud"
rm -rfv "/usr/share/doc/mangohud"
rm -fv "/usr/share/vulkan/implicit_layer.d/mangohud.json"
rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.json"
rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json"
rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json"
rm -fv "/usr/bin/mangohud"
rm -fv "/usr/bin/mangohud.x86"
}
usage() {
if test -z $1; then
echo "Unrecognized command argument: $a"
else
echo "$0 requires one argument"
fi
echo -e "\nUsage: $0 <command>\n"
echo "Available commands:"
echo -e "\tpull\t\tPull latest commits (code) from Git"
echo -e "\tconfigure\tEnsures that dependencies are installed, updates git submodules, and generates files needed for building MangoHud. This is automatically run by the build command"
echo -e "\tbuild\t\tIf needed runs configure and then builds (compiles) MangoHud"
echo -e "\tpackage\t\tRuns build if needed and then builds a tar package from MangoHud"
echo -e "\tinstall\t\tInstall MangoHud onto your system"
echo -e "\tclean\t\tRemoves build directory"
echo -e "\tuninstall\tRemoves installed MangoHud files from your system"
echo -e "\trelease\t\tBuilds a MangoHud release tar package"
}
for a in $@; do
case $a in
"") build;;
"pull") git pull;;
"configure") configure;;
"build") build;;
"package") package;;
"install") install;;
"clean") clean;;
"uninstall") uninstall;;
"release") release;;
*)
usage
esac
done
if [[ -z $@ ]]; then
usage no-args
fi

@ -237,6 +237,7 @@ usage() {
echo -e "\tbuild\t\tIf needed runs configure and then builds (compiles) MangoHud"
echo -e "\tpackage\t\tRuns build if needed and then builds a tar package from MangoHud"
echo -e "\tinstall\t\tInstall MangoHud onto your system"
echo -e "\treinstall\tRuns build, then package, and finally install"
echo -e "\tclean\t\tRemoves build directory"
echo -e "\tuninstall\tRemoves installed MangoHud files from your system"
echo -e "\trelease\t\tBuilds a MangoHud release tar package"

@ -163,6 +163,13 @@ else
dep_dl = cc.find_library('dl')
endif
# check for linking with rt by default
if cc.has_function('clock_gettime')
dep_rt = null_dep
else
dep_rt = cc.find_library('rt')
endif
if dep_vulkan.found()
datadir = get_option('datadir')
if not datadir.startswith('/')

@ -291,12 +291,15 @@ bool CPUStats::GetCpuFile() {
#ifndef NDEBUG
std::cerr << "hwmon: sensor name: " << name << std::endl;
#endif
if (name == "coretemp" && find_temp_input(path, input, "Package id 0")) {
if (name == "coretemp") {
find_temp_input(path, input, "Package id 0");
break;
}
else if ((name == "zenpower" || name == "k10temp") && find_temp_input(path, input, "Tdie")) {
else if ((name == "zenpower" || name == "k10temp")) {
find_temp_input(path, input, "Tdie");
break;
} else if (name == "atk0110" && find_temp_input(path, input, "CPU Temperature")){
} else if (name == "atk0110") {
find_temp_input(path, input, "CPU Temperature");
break;
}
}

@ -45,8 +45,6 @@ struct GLVec
struct state {
ImGuiContext *imgui_ctx = nullptr;
ImFont* font = nullptr;
ImFont* font1 = nullptr;
};
static GLVec last_vp {}, last_sb {};
@ -133,8 +131,7 @@ void imgui_create(void *ctx)
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
create_fonts(params, state.font, state.font1);
sw_stats.font1 = state.font1;
create_fonts(params, sw_stats.font1, sw_stats.font_text);
// Restore global context or ours might clash with apps that use Dear ImGui
ImGui::SetCurrentContext(saved_ctx);

@ -68,9 +68,12 @@
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <stdint.h> // intptr_t
#include <sstream>
#include <glad/glad.h>
#include "overlay.h"
namespace MangoHud {
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
@ -91,13 +94,25 @@ static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
static bool g_IsGLES = false;
// Functions
static void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
}
static bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
ImGui_ImplOpenGL3_DestroyFontsTexture();
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&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.
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
// Upload texture to graphics system
GLint last_texture;
@ -110,7 +125,7 @@ static bool ImGui_ImplOpenGL3_CreateFontsTexture()
if (g_IsGLES || g_GlVersion >= 200)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
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;
@ -121,17 +136,6 @@ static bool ImGui_ImplOpenGL3_CreateFontsTexture()
return true;
}
static 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)
{
@ -250,7 +254,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
" gl_FragColor = Frag_Color * vec4(1, 1, 1, texture2D(Texture, Frag_UV.st).r);\n"
"}\n";
const GLchar* fragment_shader_glsl_130 =
@ -260,7 +264,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
" Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\n"
"}\n";
const GLchar* fragment_shader_glsl_300_es =
@ -271,7 +275,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
" Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\n"
"}\n";
const GLchar* fragment_shader_glsl_410_core =
@ -281,7 +285,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
" Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\n"
"}\n";
#ifndef NDEBUG
@ -311,16 +315,25 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
fragment_shader = fragment_shader_glsl_130;
}
std::stringstream ss;
ss << g_GlslVersionString << vertex_shader;
std::string shader = ss.str();
// Create shaders
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
//const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
const GLchar* vertex_shader_with_version[1] = { shader.c_str() };
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
glShaderSource(g_VertHandle, 1, vertex_shader_with_version, NULL);
glCompileShader(g_VertHandle);
CheckShader(g_VertHandle, "vertex shader");
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
ss.str(""); ss.clear();
ss << g_GlslVersionString << fragment_shader;
shader = ss.str();
const GLchar* fragment_shader_with_version[1] = { shader.c_str() };
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
glShaderSource(g_FragHandle, 1, fragment_shader_with_version, NULL);
glCompileShader(g_FragHandle);
CheckShader(g_FragHandle, "fragment shader");
@ -467,6 +480,13 @@ void ImGui_ImplOpenGL3_NewFrame()
{
if (!g_ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
if (!glIsTexture(g_FontTexture)) {
#ifndef NDEBUG
fprintf(stderr, "MANGOHUD: GL Texture lost? Regenerating.\n");
#endif
g_FontTexture = 0;
ImGui_ImplOpenGL3_CreateFontsTexture();
}
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
@ -529,7 +549,7 @@ 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)
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)
return;
// Backup GL state
@ -634,7 +654,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
//#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if ((!g_IsGLES && g_GlVersion >= 320) || (g_IsGLES && g_GlVersion >= 320))
if (g_GlVersion >= 320) // OGL and OGL ES
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
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));

@ -127,10 +127,11 @@ EXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) {
do_imgui_swap(dpy, drawable);
glx.SwapBuffers(dpy, drawable);
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0){
fps_limit_stats.frameStart = os_time_get_nano();
using namespace std::chrono_literals;
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s){
fps_limit_stats.frameStart = Clock::now();
FpsLimiter(fps_limit_stats);
fps_limit_stats.frameEnd = os_time_get_nano();
fps_limit_stats.frameEnd = Clock::now();
}
}
@ -141,10 +142,11 @@ EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t targe
do_imgui_swap(dpy, drawable);
int64_t ret = glx.SwapBuffersMscOML(dpy, drawable, target_msc, divisor, remainder);
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0){
fps_limit_stats.frameStart = os_time_get_nano();
using namespace std::chrono_literals;
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s){
fps_limit_stats.frameStart = Clock::now();
FpsLimiter(fps_limit_stats);
fps_limit_stats.frameEnd = os_time_get_nano();
fps_limit_stats.frameEnd = Clock::now();
}
return ret;
}

@ -6,8 +6,7 @@
typedef unsigned long KeySym;
#endif
double elapsedF2, elapsedF12, elapsedReloadCfg, elapsedUpload;
uint64_t last_f2_press, last_f12_press, reload_cfg_press, last_upload_press;
Clock::time_point last_f2_press, last_f12_press, reload_cfg_press, last_upload_press;
#ifdef HAVE_X11
bool keys_are_pressed(const std::vector<KeySym>& keys) {

@ -5,16 +5,10 @@
string os, cpu, gpu, ram, kernel, driver;
bool sysInfoFetched = false;
int gpuLoadLog = 0, cpuLoadLog = 0;
uint64_t elapsedLog;
std::vector<std::string> logFiles;
double fps;
std::vector<logData> logArray;
ofstream out;
bool loggingOn;
uint64_t log_start, log_end;
logData currentLogData = {};
bool logUpdate = false;
std::unique_ptr<Logger> logger;
string exec(string command) {
char buffer[128];
@ -38,16 +32,16 @@ string exec(string command) {
return result;
}
void upload_file(){
void upload_file(std::string logFile){
std::string command = "curl --include --request POST https://flightlessmango.com/logs -F 'log[game_id]=26506' -F 'log[user_id]=176' -F 'attachment=true' -A 'mangohud' ";
command += " -F 'log[uploads][]=@" + logFiles.back() + "'";
command += " -F 'log[uploads][]=@" + logFile + "'";
command += " | grep Location | cut -c11-";
std::string url = exec(command);
exec("xdg-open " + url);
}
void upload_files(){
void upload_files(const std::vector<std::string>& logFiles){
std::string command = "curl --include --request POST https://flightlessmango.com/logs -F 'log[game_id]=26506' -F 'log[user_id]=176' -F 'attachment=true' -A 'mangohud' ";
for (auto& file : logFiles)
command += " -F 'log[uploads][]=@" + file + "'";
@ -58,8 +52,11 @@ void upload_files(){
}
void writeFile(string filename){
logFiles.push_back(filename);
out.open(filename, ios::out | ios::app);
auto& logArray = logger->get_log_data();
#ifndef NDEBUG
std::cerr << "Writing log file [" << filename << "], " << logArray.size() << " entries\n";
#endif
std::ofstream out(filename, ios::out | ios::app);
out << "os," << "cpu," << "gpu," << "ram," << "kernel," << "driver" << endl;
out << os << "," << cpu << "," << gpu << "," << ram << "," << kernel << "," << driver << endl;
out << "fps," << "cpu_load," << "gpu_load," << "cpu_temp," << "gpu_temp," << "gpu_core_clock," << "gpu_mem_clock," << "gpu_vram_used," << "ram_used," << "elapsed" << endl;
@ -74,11 +71,9 @@ void writeFile(string filename){
out << logArray[i].gpu_mem_clock << ",";
out << logArray[i].gpu_vram_used << ",";
out << logArray[i].ram_used << ",";
out << logArray[i].previous << "\n";
out << std::chrono::duration_cast<std::chrono::microseconds>(logArray[i].previous).count() << "\n";
}
out.close();
logArray.clear();
logger->clear_log_data();
}
string get_log_suffix(){
@ -92,23 +87,73 @@ string get_log_suffix(){
void logging(void *params_void){
overlay_params *params = reinterpret_cast<overlay_params *>(params_void);
while (loggingOn){
uint64_t now = os_time_get();
elapsedLog = now - log_start;
currentLogData.fps = fps;
currentLogData.previous = elapsedLog;
if (logUpdate)
logArray.push_back(currentLogData);
if (params->log_duration && (elapsedLog) >= params->log_duration * 1000000)
loggingOn = false;
else
if (logUpdate)
this_thread::sleep_for(chrono::milliseconds(params->log_interval));
else
this_thread::sleep_for(chrono::milliseconds(0));
logger->wait_until_data_valid();
while (logger->is_active()){
logger->try_log();
this_thread::sleep_for(chrono::milliseconds(params->log_interval));
}
}
writeFile(params->output_file + get_log_suffix());
Logger::Logger(overlay_params* in_params)
: m_logging_on(false),
m_values_valid(false),
m_params(in_params)
{
#ifndef NDEBUG
std::cerr << "Logger constructed!\n";
#endif
}
void Logger::start_logging() {
if(m_logging_on) return;
m_values_valid = false;
m_logging_on = true;
m_log_start = Clock::now();
if((not m_params->output_file.empty()) and (m_params->log_interval != 0)){
std::thread(logging, m_params).detach();
}
}
void Logger::stop_logging() {
if(not m_logging_on) return;
m_logging_on = false;
m_log_end = Clock::now();
std::thread(calculate_benchmark_data).detach();
if(not m_params->output_file.empty()) {
m_log_files.emplace_back(m_params->output_file + get_log_suffix());
std::thread(writeFile, m_log_files.back()).detach();
}
}
void Logger::try_log() {
if(not is_active()) return;
if(not m_values_valid) return;
auto now = Clock::now();
auto elapsedLog = now - m_log_start;
currentLogData.previous = elapsedLog;
currentLogData.fps = fps;
m_log_array.push_back(currentLogData);
if(m_params->log_duration and (elapsedLog >= std::chrono::seconds(m_params->log_duration))){
stop_logging();
}
}
void Logger::wait_until_data_valid() {
std::unique_lock<std::mutex> lck(m_values_valid_mtx);
while(! m_values_valid) m_values_valid_cv.wait(lck);
}
void Logger::notify_data_valid() {
std::unique_lock<std::mutex> lck(m_values_valid_mtx);
m_values_valid = true;
m_values_valid_cv.notify_all();
}
void Logger::upload_last_log() {
if(m_log_files.empty()) return;
std::thread(upload_file, m_log_files.back()).detach();
}

@ -3,8 +3,11 @@
#include <fstream>
#include <chrono>
#include <thread>
#include <condition_variable>
#include "mesa/util/os_time.h"
#include "timing.hpp"
#include "overlay_params.h"
using namespace std;
struct logData{
@ -18,23 +21,49 @@ struct logData{
float gpu_vram_used;
float ram_used;
uint64_t previous;
Clock::duration previous;
};
class Logger {
public:
Logger(overlay_params* in_params);
void start_logging();
void stop_logging();
void try_log();
bool is_active() const { return m_logging_on; }
void wait_until_data_valid();
void notify_data_valid();
auto last_log_end() const noexcept { return m_log_end; }
auto last_log_begin() const noexcept { return m_log_start; }
const std::vector<logData>& get_log_data() const noexcept { return m_log_array; }
void clear_log_data() noexcept { m_log_array.clear(); }
void upload_last_log();
private:
std::vector<logData> m_log_array;
std::vector<std::string> m_log_files;
Clock::time_point m_log_start;
Clock::time_point m_log_end;
bool m_logging_on;
std::mutex m_values_valid_mtx;
std::condition_variable m_values_valid_cv;
bool m_values_valid;
overlay_params* m_params;
};
extern std::unique_ptr<Logger> logger;
extern string os, cpu, gpu, ram, kernel, driver;
extern bool sysInfoFetched;
extern uint64_t elapsedLog;
extern std::vector<std::string> logFiles;
extern double fps;
extern std::vector<logData> logArray;
extern bool loggingOn;
extern uint64_t log_start, log_end;
extern logData currentLogData;
extern bool logUpdate;
void logging(void *params_void);
void writeFile(string filename);
string exec(string command);
string get_log_suffix(void);
void upload_file(void);
void upload_files(void);

@ -131,6 +131,7 @@ vklayer_mesa_overlay = shared_library(
libimgui_core_dep,
dbus_dep,
dep_dl,
dep_rt,
dep_pthread,
dep_vulkan],
include_directories : [inc_common],

@ -21,14 +21,19 @@ static void fileChanged(void *params_void) {
struct inotify_event *event =
(struct inotify_event *) &buffer[i];
i += EVENT_SIZE + event->len;
if (event->mask & IN_MODIFY /*|| event->mask & IN_IGNORED*/) {
if (event->mask & IN_MODIFY || event->mask & IN_DELETE_SELF) {
// In the case of IN_DELETE_SELF, some editors may to a save-to-temp-file/delete-original/move-temp-file
// so sleep a little to let file to be replaced
std::this_thread::sleep_for(std::chrono::milliseconds(100));
parse_overlay_config(&local_params, getenv("MANGOHUD_CONFIG"));
std::lock_guard<std::mutex> lk(nt->mutex);
/*if (nt->params->config_file_path != local_params.config_file_path) {
if ((event->mask & IN_DELETE_SELF) || (nt->params->config_file_path != local_params.config_file_path)) {
#ifndef NDEBUG
fprintf(stderr, "MANGOHUD: watching config file: %s\n", local_params.config_file_path.c_str());
#endif
inotify_rm_watch(nt->fd, nt->wd);
nt->wd = inotify_add_watch(nt->fd, local_params.config_file_path.c_str(), IN_MODIFY | IN_DELETE | IN_DELETE_SELF);
}*/
nt->wd = inotify_add_watch(nt->fd, local_params.config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF);
}
std::lock_guard<std::mutex> lk(nt->mutex);
*nt->params = local_params;
}
}
@ -39,13 +44,13 @@ static void fileChanged(void *params_void) {
bool start_notifier(notify_thread& nt)
{
nt.fd = inotify_init();
nt.wd = inotify_add_watch( nt.fd, nt.params->config_file_path.c_str(), IN_MODIFY);
int flags = fcntl(nt.fd, F_GETFL, 0);
if (fcntl(nt.fd, F_SETFL, flags | O_NONBLOCK))
perror("Set non-blocking failed");
nt.fd = inotify_init1(IN_NONBLOCK);
if (nt.fd < 0) {
perror("MANGOHUD: inotify_init1");
return false;
}
nt.wd = inotify_add_watch(nt.fd, nt.params->config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF);
if (nt.wd < 0) {
close(nt.fd);
nt.fd = -1;

@ -59,6 +59,7 @@
#include "blacklist.h"
#include "version.h"
#include "pci_ids.h"
#include "timing.hpp"
#ifdef HAVE_DBUS
#include "dbus_info.h"
@ -180,7 +181,6 @@ struct swapchain_data {
std::list<overlay_draw *> draws; /* List of struct overlay_draw */
ImFont* font = nullptr;
bool font_uploaded;
VkImage font_image;
VkImageView font_image_view;
@ -252,39 +252,80 @@ static void unmap_object(uint64_t obj)
/**/
void create_fonts(const overlay_params& params, ImFont*& default_font, ImFont*& small_font)
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font)
{
auto& io = ImGui::GetIO();
int font_size = params.font_size;
if (!font_size)
float font_size = params.font_size;
if (font_size < FLT_EPSILON)
font_size = 24;
static const ImWchar glyph_ranges[] =
float font_size_text = params.font_size_text;
if (font_size_text < FLT_EPSILON)
font_size_text = font_size;
static const ImWchar default_range[] =
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x0100, 0x017f, // Latin Extended-A
0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
0x2DE0, 0x2DFF, // Cyrillic Extended-A
0xA640, 0xA69F, // Cyrillic Extended-B
//0x0100, 0x017F, // Latin Extended-A
//0x2103, 0x2103, // Degree Celsius
//0x2109, 0x2109, // Degree Fahrenheit
0,
};
ImVector<ImWchar> glyph_ranges;
ImFontGlyphRangesBuilder builder;
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
if (params.font_glyph_ranges & FG_KOREAN)
builder.AddRanges(io.Fonts->GetGlyphRangesKorean());
if (params.font_glyph_ranges & FG_CHINESE_FULL)
builder.AddRanges(io.Fonts->GetGlyphRangesChineseFull());
if (params.font_glyph_ranges & FG_CHINESE_SIMPLIFIED)
builder.AddRanges(io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
if (params.font_glyph_ranges & FG_JAPANESE)
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Not exactly Shift JIS compatible?
if (params.font_glyph_ranges & FG_CYRILLIC)
builder.AddRanges(io.Fonts->GetGlyphRangesCyrillic());
if (params.font_glyph_ranges & FG_THAI)
builder.AddRanges(io.Fonts->GetGlyphRangesThai());
if (params.font_glyph_ranges & FG_VIETNAMESE)
builder.AddRanges(io.Fonts->GetGlyphRangesVietnamese());
if (params.font_glyph_ranges & FG_LATIN_EXT_A) {
static const ImWchar latin_ext_a[] { 0x0100, 0x017F, 0 };
builder.AddRanges(latin_ext_a);
}
if (params.font_glyph_ranges & FG_LATIN_EXT_B) {
static const ImWchar latin_ext_b[] { 0x0180, 0x024F, 0 };
builder.AddRanges(latin_ext_b);
}
builder.BuildRanges(&glyph_ranges);
// If both font_file and text_font_file are the same then just use "default" font
bool same_font = (params.font_file == params.font_file_text || params.font_file_text.empty());
bool same_size = (font_size == font_size_text);
// ImGui takes ownership of the data, no need to free it
if (!params.font_file.empty() && file_exists(params.font_file)) {
default_font = io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size, nullptr, glyph_ranges);
small_font = io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f, nullptr, io.Fonts->GetGlyphRangesDefault());
io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size, nullptr, same_font && same_size ? glyph_ranges.Data : default_range);
small_font = io.Fonts->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f, nullptr, default_range);
} else {
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
default_font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, nullptr, io.Fonts->GetGlyphRangesDefault());
small_font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55, nullptr, io.Fonts->GetGlyphRangesDefault());
io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, nullptr, default_range);
small_font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55f, nullptr, default_range);
}
}
// FIXME "temporary" hack until Dear ImGui has an actual API for this
void scale_default_font(ImFont& scaled_font, float scale)
{
scaled_font = *ImGui::GetIO().Fonts->Fonts[0];
scaled_font.Scale = scale;
auto font_file_text = params.font_file_text;
if (font_file_text.empty())
font_file_text = params.font_file;
if ((!same_font || !same_size) && file_exists(font_file_text))
text_font = io.Fonts->AddFontFromFileTTF(font_file_text.c_str(), font_size_text, nullptr, glyph_ranges.Data);
else
text_font = io.Fonts->Fonts[0];
io.Fonts->Build();
}
static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
@ -694,17 +735,17 @@ void init_system_info(){
}
void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID){
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_stats] || loggingOn) {
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_stats] || logger->is_active()) {
cpuStats.UpdateCPUData();
sw_stats.total_cpu = cpuStats.GetCPUDataTotal().percent;
if (params.enabled[OVERLAY_PARAM_ENABLED_core_load])
cpuStats.UpdateCoreMhz();
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_temp] || loggingOn)
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_temp] || logger->is_active())
cpuStats.UpdateCpuTemp();
}
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] || loggingOn) {
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] || logger->is_active()) {
if (vendorID == 0x1002)
getAmdGpuInfo();
@ -713,7 +754,7 @@ void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& par
}
// get ram usage/max
if (params.enabled[OVERLAY_PARAM_ENABLED_ram] || loggingOn)
if (params.enabled[OVERLAY_PARAM_ENABLED_ram] || logger->is_active())
update_meminfo();
if (params.enabled[OVERLAY_PARAM_ENABLED_io_read] || params.enabled[OVERLAY_PARAM_ENABLED_io_write])
getIoStats(&sw_stats.io);
@ -728,46 +769,42 @@ void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& par
currentLogData.cpu_load = cpuStats.GetCPUDataTotal().percent;
currentLogData.cpu_temp = cpuStats.GetCPUDataTotal().temp;
if (!logUpdate)
logUpdate = true;
logger->notify_data_valid();
}
void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID){
using namespace std::chrono_literals;
bool pressed = false; // FIXME just a placeholder until wayland support
uint64_t now = os_time_get(); /* us */
elapsedF2 = (double)(now - last_f2_press);
elapsedF12 = (double)(now - last_f12_press);
elapsedReloadCfg = (double)(now - reload_cfg_press);
elapsedUpload = (double)(now - last_upload_press);
auto now = Clock::now(); /* us */
auto elapsedF2 = now - last_f2_press;
auto elapsedF12 = now - last_f12_press;
auto elapsedReloadCfg = now - reload_cfg_press;
auto elapsedUpload = now - last_upload_press;
auto keyPressDelay = 500ms;
if (elapsedF2 >= 500000){
if (elapsedF2 >= keyPressDelay){
#ifdef HAVE_X11
pressed = keys_are_pressed(params.toggle_logging);
#else
pressed = false;
#endif
if (pressed && (now - log_end) / 1000000 > 11){
if (pressed && (now - logger->last_log_end() > 11s)) {
last_f2_press = now;
if(loggingOn){
log_end = now;
std::thread(calculate_benchmark_data, &params).detach();
if (logger->is_active()) {
logger->stop_logging();
} else {
logUpdate = false;
std::thread(update_hw_info, std::ref(sw_stats), std::ref(params), vendorID).detach();
logger->start_logging();
std::thread(update_hw_info, std::ref(sw_stats), std::ref(params),
vendorID)
.detach();
benchmark.fps_data.clear();
log_start = now;
}
if (!params.output_file.empty() && params.log_duration == 0 && params.log_interval == 0 && loggingOn)
writeFile(params.output_file + get_log_suffix());
loggingOn = !loggingOn;
if (!params.output_file.empty() && loggingOn && params.log_interval != 0)
std::thread(logging, &params).detach();
}
}
if (elapsedF12 >= 500000){
if (elapsedF12 >= keyPressDelay){
#ifdef HAVE_X11
pressed = keys_are_pressed(params.toggle_hud);
#else
@ -779,7 +816,7 @@ void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& par
}
}
if (elapsedReloadCfg >= 500000){
if (elapsedReloadCfg >= keyPressDelay){
#ifdef HAVE_X11
pressed = keys_are_pressed(params.reload_cfg);
#else
@ -791,7 +828,7 @@ void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& par
}
}
if (params.permit_upload && elapsedUpload >= 500000){
if (params.permit_upload && elapsedUpload >= keyPressDelay){
#ifdef HAVE_X11
pressed = keys_are_pressed(params.upload_log);
#else
@ -799,8 +836,7 @@ void check_keybinds(struct swapchain_stats& sw_stats, struct overlay_params& par
#endif
if (pressed){
last_upload_press = now;
if (logFiles.size() > 0)
std::thread(upload_file).detach();
logger->upload_last_log();
}
}
}
@ -845,12 +881,13 @@ void calculate_benchmark_data(void *params_void){
}
void update_hud_info(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID){
if(not logger) logger = std::make_unique<Logger>(&params);
uint32_t f_idx = sw_stats.n_frames % ARRAY_SIZE(sw_stats.frames_stats);
uint64_t now = os_time_get(); /* us */
double elapsed = (double)(now - sw_stats.last_fps_update); /* us */
fps = 1000000.0f * sw_stats.n_frames_since_update / elapsed;
if (loggingOn)
if (logger->is_active())
benchmark.fps_data.push_back(fps);
if (sw_stats.last_present_time) {
@ -1054,7 +1091,7 @@ static void render_mpris_metadata(struct overlay_params& params, metadata& meta,
}
#endif
void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, unsigned height, uint64_t now){
void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, unsigned height, Clock::time_point now){
// TODO, FIX LOG_DURATION FOR BENCHMARK
int benchHeight = (2 + benchmark.percentile_data.size()) * params.font_size + 10.0f + 58;
ImGui::SetNextWindowSize(ImVec2(window_size.x, benchHeight), ImGuiCond_Always);
@ -1063,7 +1100,8 @@ void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVe
else
ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y + window_size.y + 5), ImGuiCond_Always);
float display_time = float(now - log_end) / 1000000;
vector<pair<string, float>> benchmark_data = {{"97% ", benchmark.ninety}, {"AVG ", benchmark.avg}, {"1% ", benchmark.oneP}, {"0.1%", benchmark.pointOneP}};
float display_time = std::chrono::duration<float>(now - logger->last_log_end()).count();
static float display_for = 10.0f;
float alpha;
if(params.background_alpha != 0){
@ -1097,7 +1135,7 @@ void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVe
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", finished);
ImGui::Dummy(ImVec2(0.0f, 8.0f));
char duration[20];
snprintf(duration, sizeof(duration), "Duration: %.1fs", float(log_end - log_start) / 1000000);
snprintf(duration, sizeof(duration), "Duration: %.1fs", std::chrono::duration<float>(logger->last_log_end() - logger->last_log_begin()).count());
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(duration).x / 2));
ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", duration);
for (auto& data_ : benchmark.percentile_data){
@ -1122,12 +1160,14 @@ void render_benchmark(swapchain_stats& data, struct overlay_params& params, ImVe
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan)
{
ImGui::GetIO().FontGlobalScale = params.font_scale;
if(not logger) logger = std::make_unique<Logger>(&params);
uint32_t f_idx = (data.n_frames - 1) % ARRAY_SIZE(data.frames_stats);
uint64_t frame_timing = data.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing];
static float char_width = ImGui::CalcTextSize("A").x;
window_size = ImVec2(params.width, params.height);
unsigned height = ImGui::GetIO().DisplaySize.y;
uint64_t now = os_time_get();
auto now = Clock::now();
if (!params.no_display){
ImGui::Begin("Main", &open, ImGuiWindowFlags_NoDecoration);
@ -1349,18 +1389,12 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
ImGui::PopFont();
}
if (loggingOn && params.log_interval == 0){
elapsedLog = (double)(now - log_start);
if (params.log_duration && (elapsedLog) >= params.log_duration * 1000000)
loggingOn = false;
currentLogData.fps = fps;
currentLogData.previous = elapsedLog;
logArray.push_back(currentLogData);
if (params.log_interval == 0){
logger->try_log();
}
if (params.enabled[OVERLAY_PARAM_ENABLED_frame_timing]){
ImGui::Dummy(ImVec2(0.0f, params.font_size / 2));
ImGui::Dummy(ImVec2(0.0f, params.font_size * params.font_scale / 2));
ImGui::PushFont(data.font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.engine_color), "%s", "Frametime");
ImGui::PopFont();
@ -1377,12 +1411,12 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
ImGui::PlotHistogram(hash, get_time_stat, &data,
ARRAY_SIZE(data.frames_stats), 0,
NULL, min_time, max_time,
ImVec2(ImGui::GetContentRegionAvailWidth() - params.font_size * 2.2, 50));
ImVec2(ImGui::GetContentRegionAvailWidth() - params.font_size * params.font_scale * 2.2, 50));
} else {
ImGui::PlotLines(hash, get_time_stat, &data,
ARRAY_SIZE(data.frames_stats), 0,
NULL, min_time, max_time,
ImVec2(ImGui::GetContentRegionAvailWidth() - params.font_size * 2.2, 50));
ImVec2(ImGui::GetContentRegionAvailWidth() - params.font_size * params.font_scale * 2.2, 50));
}
ImGui::PopStyleColor();
}
@ -1394,26 +1428,20 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
}
#ifdef HAVE_DBUS
ImFont scaled_font;
scale_default_font(scaled_font, params.font_scale_media_player);
ImFont scaled_font = *data.font_text;
scaled_font.Scale = params.font_scale_media_player;
ImGui::PushFont(&scaled_font);
render_mpris_metadata(params, main_metadata, frame_timing, true);
render_mpris_metadata(params, generic_mpris, frame_timing, false);
ImGui::PopFont();
#endif
if(loggingOn)
if(logger->is_active())
ImGui::GetWindowDrawList()->AddCircleFilled(ImVec2(data.main_window_pos.x + window_size.x - 15, data.main_window_pos.y + 15), 10, params.engine_color, 20);
window_size = ImVec2(window_size.x, ImGui::GetCursorPosY() + 10.0f);
ImGui::End();
if (loggingOn && params.log_duration && (now - log_start) >= params.log_duration * 1000000){
loggingOn = false;
log_end = now;
std::thread(calculate_benchmark_data, &params).detach();
}
if((now - log_end) / 1000000 < 12)
if((now - logger->last_log_end()) < 12s)
render_benchmark(data, params, window_size, height, now);
}
}
@ -1447,21 +1475,33 @@ static uint32_t vk_memory_type(struct device_data *data,
return 0xFFFFFFFF; // Unable to find memoryType
}
static void ensure_swapchain_fonts(struct swapchain_data *data,
VkCommandBuffer command_buffer)
static void update_image_descriptor(struct swapchain_data *data, VkImageView image_view, VkDescriptorSet set)
{
if (data->font_uploaded)
return;
data->font_uploaded = true;
struct device_data *device_data = data->device;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
size_t upload_size = width * height * 4 * sizeof(char);
/* Descriptor set */
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = data->font_sampler;
desc_image[0].imageView = image_view;
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = set;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL);
}
static void upload_image_data(struct device_data *device_data,
VkCommandBuffer command_buffer,
void *pixels,
VkDeviceSize upload_size,
uint32_t width,
uint32_t height,
VkBuffer& upload_buffer,
VkDeviceMemory& upload_buffer_mem,
VkImage image)
{
/* Upload buffer */
VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
@ -1469,10 +1509,10 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK(device_data->vtable.CreateBuffer(device_data->device, &buffer_info,
NULL, &data->upload_font_buffer));
NULL, &upload_buffer));
VkMemoryRequirements upload_buffer_req;
device_data->vtable.GetBufferMemoryRequirements(device_data->device,
data->upload_font_buffer,
upload_buffer,
&upload_buffer_req);
VkMemoryAllocateInfo upload_alloc_info = {};
upload_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
@ -1483,24 +1523,24 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
VK_CHECK(device_data->vtable.AllocateMemory(device_data->device,
&upload_alloc_info,
NULL,
&data->upload_font_buffer_mem));
&upload_buffer_mem));
VK_CHECK(device_data->vtable.BindBufferMemory(device_data->device,
data->upload_font_buffer,
data->upload_font_buffer_mem, 0));
upload_buffer,
upload_buffer_mem, 0));
/* Upload to Buffer */
char* map = NULL;
VK_CHECK(device_data->vtable.MapMemory(device_data->device,
data->upload_font_buffer_mem,
upload_buffer_mem,
0, upload_size, 0, (void**)(&map)));
memcpy(map, pixels, upload_size);
VkMappedMemoryRange range[1] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = data->upload_font_buffer_mem;
range[0].memory = upload_buffer_mem;
range[0].size = upload_size;
VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 1, range));
device_data->vtable.UnmapMemory(device_data->device,
data->upload_font_buffer_mem);
upload_buffer_mem);
/* Copy buffer to image */
VkImageMemoryBarrier copy_barrier[1] = {};
@ -1510,7 +1550,7 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
copy_barrier[0].image = data->font_image;
copy_barrier[0].image = image;
copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_barrier[0].subresourceRange.levelCount = 1;
copy_barrier[0].subresourceRange.layerCount = 1;
@ -1527,8 +1567,8 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
region.imageExtent.height = height;
region.imageExtent.depth = 1;
device_data->vtable.CmdCopyBufferToImage(command_buffer,
data->upload_font_buffer,
data->font_image,
upload_buffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &region);
@ -1540,7 +1580,7 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
use_barrier[0].image = data->font_image;
use_barrier[0].image = image;
use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
use_barrier[0].subresourceRange.levelCount = 1;
use_barrier[0].subresourceRange.layerCount = 1;
@ -1551,9 +1591,90 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
0, NULL,
0, NULL,
1, use_barrier);
}
static VkDescriptorSet create_image_with_desc(struct swapchain_data *data,
uint32_t width,
uint32_t height,
VkFormat format,
VkImage& image,
VkDeviceMemory& image_mem,
VkImageView& image_view)
{
struct device_data *device_data = data->device;
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = format;
image_info.extent.width = width;
image_info.extent.height = height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info,
NULL, &image));
VkMemoryRequirements font_image_req;
device_data->vtable.GetImageMemoryRequirements(device_data->device,
image, &font_image_req);
VkMemoryAllocateInfo image_alloc_info = {};
image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
image_alloc_info.allocationSize = font_image_req.size;
image_alloc_info.memoryTypeIndex = vk_memory_type(device_data,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
font_image_req.memoryTypeBits);
VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info,
NULL, &image_mem));
VK_CHECK(device_data->vtable.BindImageMemory(device_data->device,
image,
image_mem, 0));
/* Font image view */
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.image = image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.layerCount = 1;
VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info,
NULL, &image_view));
VkDescriptorSet descriptor_set;
/* Store our identifier */
io.Fonts->TexID = (ImTextureID)(intptr_t)data->font_image;
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = data->descriptor_pool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &data->descriptor_layout;
VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,
&alloc_info,
&descriptor_set));
update_image_descriptor(data, image_view, descriptor_set);
return descriptor_set;
}
static void ensure_swapchain_fonts(struct swapchain_data *data,
VkCommandBuffer command_buffer)
{
struct device_data *device_data = data->device;
if (data->font_uploaded)
return;
data->font_uploaded = true;
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
size_t upload_size = width * height * 1 * sizeof(char);
upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image);
}
static void CreateOrResizeBuffer(struct device_data *data,
@ -1663,100 +1784,110 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
}
/* Upload vertex & index data */
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->vertex_buffer_mem,
0, vertex_size, 0, (void**)(&vtx_dst)));
VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->index_buffer_mem,
0, index_size, 0, (void**)(&idx_dst)));
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = draw->vertex_buffer_mem;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[1].memory = draw->index_buffer_mem;
range[1].size = VK_WHOLE_SIZE;
VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 2, range));
device_data->vtable.UnmapMemory(device_data->device, draw->vertex_buffer_mem);
device_data->vtable.UnmapMemory(device_data->device, draw->index_buffer_mem);
/* Bind pipeline and descriptor sets */
device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline);
VkDescriptorSet desc_set[1] = { data->descriptor_set };
device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
data->pipeline_layout, 0, 1, desc_set, 0, NULL);
/* Bind vertex & index buffers */
VkBuffer vertex_buffers[1] = { draw->vertex_buffer };
VkDeviceSize vertex_offset[1] = { 0 };
device_data->vtable.CmdBindVertexBuffers(draw->command_buffer, 0, 1, vertex_buffers, vertex_offset);
device_data->vtable.CmdBindIndexBuffer(draw->command_buffer, draw->index_buffer, 0, VK_INDEX_TYPE_UINT16);
/* Setup viewport */
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = draw_data->DisplaySize.x;
viewport.height = draw_data->DisplaySize.y;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
device_data->vtable.CmdSetViewport(draw->command_buffer, 0, 1, &viewport);
/* Setup scale and translation through push constants :
*
* Our visible imgui space lies from draw_data->DisplayPos (top left) to
* draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin
* is typically (0,0) for single viewport apps.
*/
float scale[2];
scale[0] = 2.0f / draw_data->DisplaySize.x;
scale[1] = 2.0f / draw_data->DisplaySize.y;
float translate[2];
translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];
translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];
device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT,
sizeof(float) * 0, sizeof(float) * 2, scale);
device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT,
sizeof(float) * 2, sizeof(float) * 2, translate);
// Render the command lists:
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 display_pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
// Apply scissor/clipping rectangle
// FIXME: We could clamp width/height based on clamped min/max values.
VkRect2D scissor;
scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0;
scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0;
scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?
device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor);
// Draw
device_data->vtable.CmdDrawIndexed(draw->command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);
idx_offset += pcmd->ElemCount;
}
vtx_offset += cmd_list->VtxBuffer.Size;
}
/* Upload vertex & index data */
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->vertex_buffer_mem,
0, vertex_size, 0, (void**)(&vtx_dst)));
VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->index_buffer_mem,
0, index_size, 0, (void**)(&idx_dst)));
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = draw->vertex_buffer_mem;
range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[1].memory = draw->index_buffer_mem;
range[1].size = VK_WHOLE_SIZE;
VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 2, range));
device_data->vtable.UnmapMemory(device_data->device, draw->vertex_buffer_mem);
device_data->vtable.UnmapMemory(device_data->device, draw->index_buffer_mem);
/* Bind pipeline and descriptor sets */
device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline);
#if 1 // disable if using >1 font textures
VkDescriptorSet desc_set[1] = {
//data->descriptor_set
reinterpret_cast<VkDescriptorSet>(ImGui::GetIO().Fonts->Fonts[0]->ContainerAtlas->TexID)
};
device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
data->pipeline_layout, 0, 1, desc_set, 0, NULL);
#endif
/* Bind vertex & index buffers */
VkBuffer vertex_buffers[1] = { draw->vertex_buffer };
VkDeviceSize vertex_offset[1] = { 0 };
device_data->vtable.CmdBindVertexBuffers(draw->command_buffer, 0, 1, vertex_buffers, vertex_offset);
device_data->vtable.CmdBindIndexBuffer(draw->command_buffer, draw->index_buffer, 0, VK_INDEX_TYPE_UINT16);
/* Setup viewport */
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = draw_data->DisplaySize.x;
viewport.height = draw_data->DisplaySize.y;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
device_data->vtable.CmdSetViewport(draw->command_buffer, 0, 1, &viewport);
/* Setup scale and translation through push constants :
*
* Our visible imgui space lies from draw_data->DisplayPos (top left) to
* draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin
* is typically (0,0) for single viewport apps.
*/
float scale[2];
scale[0] = 2.0f / draw_data->DisplaySize.x;
scale[1] = 2.0f / draw_data->DisplaySize.y;
float translate[2];
translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];
translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];
device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT,
sizeof(float) * 0, sizeof(float) * 2, scale);
device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT,
sizeof(float) * 2, sizeof(float) * 2, translate);
// Render the command lists:
int vtx_offset = 0;
int idx_offset = 0;
ImVec2 display_pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
// Apply scissor/clipping rectangle
// FIXME: We could clamp width/height based on clamped min/max values.
VkRect2D scissor;
scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0;
scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0;
scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?
device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor);
#if 0 //enable if using >1 font textures or use texture array
VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
data->pipeline_layout, 0, 1, desc_set, 0, NULL);
#endif
// Draw
device_data->vtable.CmdDrawIndexed(draw->command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);
idx_offset += pcmd->ElemCount;
}
vtx_offset += cmd_list->VtxBuffer.Size;
}
device_data->vtable.CmdEndRenderPass(draw->command_buffer);
@ -1907,6 +2038,7 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data)
NULL, &data->descriptor_layout));
/* Descriptor set */
/*
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = data->descriptor_pool;
@ -1915,6 +2047,7 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data)
VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,
&alloc_info,
&data->descriptor_set));
*/
/* Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full
* 3d projection matrix
@ -2036,68 +2169,21 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data)
device_data->vtable.DestroyShaderModule(device_data->device, vert_module, NULL);
device_data->vtable.DestroyShaderModule(device_data->device, frag_module, NULL);
create_fonts(device_data->instance->params, data->sw_stats.font1, data->sw_stats.font_text);
ImGuiIO& io = ImGui::GetIO();
create_fonts(device_data->instance->params, data->font, data->sw_stats.font1);
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
/* Font image */
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_info.extent.width = width;
image_info.extent.height = height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info,
NULL, &data->font_image));
VkMemoryRequirements font_image_req;
device_data->vtable.GetImageMemoryRequirements(device_data->device,
data->font_image, &font_image_req);
VkMemoryAllocateInfo image_alloc_info = {};
image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
image_alloc_info.allocationSize = font_image_req.size;
image_alloc_info.memoryTypeIndex = vk_memory_type(device_data,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
font_image_req.memoryTypeBits);
VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info,
NULL, &data->font_mem));
VK_CHECK(device_data->vtable.BindImageMemory(device_data->device,
data->font_image,
data->font_mem, 0));
/* Font image view */
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.image = data->font_image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = VK_FORMAT_R8G8B8A8_UNORM;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.layerCount = 1;
VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info,
NULL, &data->font_image_view));
// upload default font to VkImage
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
io.Fonts->TexID = (ImTextureID)create_image_with_desc(data, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view);
#ifndef NDEBUG
std::cerr << "MANGOHUD: Default font tex size: " << width << "x" << height << "px (" << (width*height*1) << " bytes)" << "\n";
#endif
/* Descriptor set */
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = data->font_sampler;
desc_image[0].imageView = data->font_image_view;
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = data->descriptor_set;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL);
// if (data->descriptor_set)
// update_image_descriptor(data, data->font_image_view[0], data->descriptor_set);
}
void imgui_custom_style(struct overlay_params& params){
@ -2392,11 +2478,11 @@ static void overlay_DestroySwapchainKHR(
void FpsLimiter(struct fps_limit& stats){
stats.sleepTime = stats.targetFrameTime - (stats.frameStart - stats.frameEnd);
if (stats.sleepTime > stats.frameOverhead) {
int64_t adjustedSleep = stats.sleepTime - stats.frameOverhead;
this_thread::sleep_for(chrono::nanoseconds(adjustedSleep));
stats.frameOverhead = ((os_time_get_nano() - stats.frameStart) - adjustedSleep);
auto adjustedSleep = stats.sleepTime - stats.frameOverhead;
this_thread::sleep_for(adjustedSleep);
stats.frameOverhead = ((Clock::now() - stats.frameStart) - adjustedSleep);
if (stats.frameOverhead > stats.targetFrameTime)
stats.frameOverhead = 0;
stats.frameOverhead = Clock::duration(0);
}
}
@ -2446,10 +2532,12 @@ static VkResult overlay_QueuePresentKHR(
result = chain_result;
}
if (fps_limit_stats.targetFrameTime > 0){
fps_limit_stats.frameStart = os_time_get_nano();
using namespace std::chrono_literals;
if (fps_limit_stats.targetFrameTime > 0s){
fps_limit_stats.frameStart = Clock::now();
FpsLimiter(fps_limit_stats);
fps_limit_stats.frameEnd = os_time_get_nano();
fps_limit_stats.frameEnd = Clock::now();
}
return result;
@ -2719,9 +2807,9 @@ static VkResult overlay_CreateInstance(
// Adjust height for DXVK/VKD3D version number
if (engineName == "DXVK" || engineName == "VKD3D"){
if (instance_data->params.font_size){
instance_data->params.height += instance_data->params.font_size / 2;
instance_data->params.height += instance_data->params.font_size * instance_data->params.font_scale / 2;
} else {
instance_data->params.height += 24 / 2;
instance_data->params.height += 24 * instance_data->params.font_scale / 2;
}
}

@ -10,5 +10,5 @@ layout(location = 0) in struct{
void main()
{
fColor = In.Color * texture(sTexture, In.UV.st);
fColor = In.Color * vec4(1, 1, 1, texture(sTexture, In.UV.st).r);
}

@ -1,9 +1,12 @@
#pragma once
#include <string>
#include <stdint.h>
#include <vector>
#include "imgui.h"
#include "overlay_params.h"
#include "iostats.h"
#include "timing.hpp"
struct frame_stat {
uint64_t stats[OVERLAY_PLOTS_MAX];
@ -17,6 +20,7 @@ struct swapchain_stats {
struct frame_stat frames_stats[200];
ImFont* font1 = nullptr;
ImFont* font_text = nullptr;
std::string time;
double fps;
struct iostats io;
@ -44,11 +48,11 @@ struct swapchain_stats {
};
struct fps_limit {
int64_t frameStart;
int64_t frameEnd;
int64_t targetFrameTime;
int64_t frameOverhead;
int64_t sleepTime;
Clock::time_point frameStart;
Clock::time_point frameEnd;
Clock::duration targetFrameTime;
Clock::duration frameOverhead;
Clock::duration sleepTime;
};
struct benchmark_stats {
@ -72,5 +76,5 @@ void init_system_info(void);
void FpsLimiter(struct fps_limit& stats);
void imgui_custom_style(struct overlay_params& params);
void get_device_name(int32_t vendorID, int32_t deviceID, struct swapchain_stats& sw_stats);
void calculate_benchmark_data(void *params_void);
void create_fonts(const overlay_params& params, ImFont*& default_font, ImFont*& small_font);
void calculate_benchmark_data(void);
void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font);

@ -202,6 +202,7 @@ parse_media_player_order(const char *str)
return order;
}
static std::vector<std::string>
parse_benchmark_percentiles(const char *str)
{
@ -241,6 +242,38 @@ parse_benchmark_percentiles(const char *str)
}
return percentiles;
static uint32_t
parse_font_glyph_ranges(const char *str)
{
uint32_t fg = 0;
std::stringstream ss(str);
std::string token;
while (std::getline(ss, token, ',')) {
trim(token);
std::transform(token.begin(), token.end(), token.begin(), ::tolower);
if (token == "korean")
fg |= FG_KOREAN;
else if (token == "chinese")
fg |= FG_CHINESE_FULL;
else if (token == "chinese_simplified")
fg |= FG_CHINESE_SIMPLIFIED;
else if (token == "japanese")
fg |= FG_JAPANESE;
else if (token == "cyrillic")
fg |= FG_CYRILLIC;
else if (token == "thai")
fg |= FG_THAI;
else if (token == "vietnamese")
fg |= FG_VIETNAMESE;
else if (token == "latin_ext_a")
fg |= FG_LATIN_EXT_A;
else if (token == "latin_ext_b")
fg |= FG_LATIN_EXT_B;
}
return fg;
}
#define parse_width(s) parse_unsigned(s)
@ -253,6 +286,7 @@ parse_benchmark_percentiles(const char *str)
#define parse_time_format(s) parse_str(s)
#define parse_output_file(s) parse_path(s)
#define parse_font_file(s) parse_path(s)
#define parse_font_file_text(s) parse_path(s)
#define parse_io_read(s) parse_unsigned(s)
#define parse_io_write(s) parse_unsigned(s)
#define parse_pci_dev(s) parse_str(s)
@ -262,6 +296,8 @@ parse_benchmark_percentiles(const char *str)
#define parse_gpu_text(s) parse_str(s)
#define parse_log_interval(s) parse_unsigned(s)
#define parse_font_size(s) parse_float(s)
#define parse_font_size_text(s) parse_float(s)
#define parse_font_scale(s) parse_float(s)
#define parse_background_alpha(s) parse_float(s)
#define parse_alpha(s) parse_float(s)
#define parse_permit_upload(s) parse_unsigned(s)
@ -430,6 +466,7 @@ parse_overlay_config(struct overlay_params *params,
params->text_color = 0xffffff;
params->media_player_color = 0xffffff;
params->media_player_name = "spotify";
params->font_scale = 1.0f;
params->font_scale_media_player = 0.55f;
params->log_interval = 100;
params->media_player_order = { MP_ORDER_TITLE, MP_ORDER_ARTIST, MP_ORDER_ALBUM };
@ -520,15 +557,16 @@ parse_overlay_config(struct overlay_params *params,
//increase hud width if io read and write
if (!params->width) {
if ((params->enabled[OVERLAY_PARAM_ENABLED_io_read] || params->enabled[OVERLAY_PARAM_ENABLED_io_write])) {
params->width = 13 * params->font_size;
params->width = 13 * params->font_size * params->font_scale;
} else {
params->width = params->font_size * 11.7;
params->width = params->font_size * params->font_scale * 11.7;
}
}
// set frametime limit
using namespace std::chrono;
if (params->fps_limit >= 0)
fps_limit_stats.targetFrameTime = int64_t(1000000000.0 / params->fps_limit);
fps_limit_stats.targetFrameTime = duration_cast<Clock::duration>(duration<double>(1) / params->fps_limit);
#ifdef HAVE_DBUS
if (params->enabled[OVERLAY_PARAM_ENABLED_media_player]) {

@ -51,6 +51,12 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(fps_sampling_period) \
OVERLAY_PARAM_CUSTOM(output_file) \
OVERLAY_PARAM_CUSTOM(font_file) \
OVERLAY_PARAM_CUSTOM(font_file_text) \
OVERLAY_PARAM_CUSTOM(font_glyph_ranges) \
OVERLAY_PARAM_CUSTOM(font_size) \
OVERLAY_PARAM_CUSTOM(font_size_text) \
OVERLAY_PARAM_CUSTOM(font_scale) \
OVERLAY_PARAM_CUSTOM(font_scale_media_player) \
OVERLAY_PARAM_CUSTOM(position) \
OVERLAY_PARAM_CUSTOM(width) \
OVERLAY_PARAM_CUSTOM(height) \
@ -59,8 +65,6 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(fps_limit) \
OVERLAY_PARAM_CUSTOM(vsync) \
OVERLAY_PARAM_CUSTOM(gl_vsync) \
OVERLAY_PARAM_CUSTOM(font_size) \
OVERLAY_PARAM_CUSTOM(font_scale_media_player) \
OVERLAY_PARAM_CUSTOM(toggle_hud) \
OVERLAY_PARAM_CUSTOM(toggle_logging) \
OVERLAY_PARAM_CUSTOM(reload_cfg) \
@ -112,6 +116,18 @@ enum media_player_order {
MP_ORDER_ALBUM,
};
enum font_glyph_ranges {
FG_KOREAN = (1u << 0),
FG_CHINESE_FULL = (1u << 1),
FG_CHINESE_SIMPLIFIED = (1u << 2),
FG_JAPANESE = (1u << 3),
FG_CYRILLIC = (1u << 4),
FG_THAI = (1u << 5),
FG_VIETNAMESE = (1u << 6),
FG_LATIN_EXT_A = (1u << 7),
FG_LATIN_EXT_B = (1u << 8),
};
enum overlay_param_enabled {
#define OVERLAY_PARAM_BOOL(name) OVERLAY_PARAM_ENABLED_##name,
#define OVERLAY_PARAM_CUSTOM(name)
@ -140,14 +156,15 @@ struct overlay_params {
unsigned cpu_color, gpu_color, vram_color, ram_color, engine_color, io_color, frametime_color, background_color, text_color;
unsigned media_player_color;
unsigned tableCols;
float font_size;
float font_size, font_scale;
float font_size_text;
float font_scale_media_player;
float background_alpha, alpha;
std::vector<KeySym> toggle_hud;
std::vector<KeySym> toggle_logging;
std::vector<KeySym> reload_cfg;
std::vector<KeySym> upload_log;
std::string time_format, output_file, font_file;
std::string time_format, output_file;
std::string pci_dev;
std::string media_player_name;
std::string cpu_text, gpu_text;
@ -155,6 +172,9 @@ struct overlay_params {
std::vector<media_player_order> media_player_order;
std::vector<std::string> benchmark_percentiles;
std::string font_file, font_file_text;
uint32_t font_glyph_ranges;
std::string config_file_path;
std::unordered_map<std::string,std::string> options;
int permit_upload;

@ -0,0 +1,20 @@
#ifndef MANGOHUD_TIMING_HPP
#define MANGOHUD_TIMING_HPP
#include <chrono>
#include "mesa/util/os_time.h"
class MesaClock {
public:
using rep = int64_t;
using period = std::nano;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<MesaClock>;
const static bool is_steady = true;
static time_point now() noexcept {
return time_point(duration(os_time_get_nano()));
}
};
using Clock = MesaClock;
#endif //MANGOHUD_TIMING_HPP
Loading…
Cancel
Save