Merge opengl into develop

pull/58/head
FlightlessMango 4 years ago
parent a5c0d39519
commit a2735693ba

@ -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 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 LD_LIBRARY_PATH="$LD_LIBRARY_PATH" LD_PRELOAD="${LD_PRELOAD}" "$@"

@ -142,6 +142,7 @@ package() {
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 --preserve=mode "bin/run-mangohud-gl.sh" "build/package/MangoHud/run-mangohud-gl.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"

@ -25,6 +25,10 @@
#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,
@ -98,6 +102,7 @@ CPUStats::CPUStats()
bool CPUStats::Init()
{
CPUStats::GetCpuFile();
std::string line;
std::ifstream file (PROCSTATFILE);
bool first = true;
@ -145,6 +150,7 @@ bool CPUStats::Init()
bool CPUStats::UpdateCPUData()
{
CPUStats::UpdateCoreMhz();
CPUStats::UpdateCpuTemp();
unsigned long long int usertime, nicetime, systemtime, idletime;
unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
int cpuid = -1;
@ -214,4 +220,38 @@ bool CPUStats::UpdateCoreMhz() {
return true;
}
bool CPUStats::UpdateCpuTemp(){
rewind(cpuTempFile);
fflush(cpuTempFile);
if (fscanf(cpuTempFile, "%d", &m_cpuDataTotal.temp) != 1)
m_cpuDataTotal.temp = 0;
m_cpuDataTotal.temp /= 1000;
return NULL;
}
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;

@ -29,6 +29,7 @@ typedef struct CPUData_ {
unsigned long long int guestPeriod;
float percent;
int mhz;
int temp;
} CPUData;
class CPUStats
@ -43,6 +44,8 @@ public:
bool UpdateCPUData();
bool UpdateCoreMhz();
bool UpdateCpuTemp();
bool GetCpuFile();
double GetCPUPeriod() { return m_cpuPeriod; }
const std::vector<CPUData>& GetCPUData() const {

@ -1,139 +0,0 @@
#include <thread>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "nvidia_info.h"
#include "memory.h"
using namespace std;
int gpuLoad = 0, gpuTemp = 0, cpuTemp = 0, gpuMemClock, gpuCoreClock;
FILE *amdGpuFile = nullptr, *amdTempFile = nullptr, *cpuTempFile = nullptr, *amdGpuVramTotalFile = nullptr, *amdGpuVramUsedFile = nullptr, *amdGpuCoreClockFile = nullptr, *amdGpuMemoryClockFile = 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;
int MemClock;
int CoreClock;
};
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 = nvidiaMemory.used / (1024.f * 1024.f * 1024.f);
gpuCoreClock = nvidiaCoreClock;
gpuMemClock = 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;
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, &value) != 1)
value = 0;
amdgpu.memoryTotal = value / (1024 * 1024);
gpuMemTotal = amdgpu.memoryTotal;
}
if (amdGpuVramUsedFile) {
rewind(amdGpuVramUsedFile);
fflush(amdGpuVramUsedFile);
if (fscanf(amdGpuVramUsedFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.memoryUsed = value / (1024 * 1024);
gpuMemUsed = amdgpu.memoryUsed / 1024.f;
}
if (amdGpuCoreClockFile) {
rewind(amdGpuCoreClockFile);
fflush(amdGpuCoreClockFile);
if (fscanf(amdGpuCoreClockFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.CoreClock = value / 1000000;
gpuCoreClock = amdgpu.CoreClock;
}
if (amdGpuMemoryClockFile) {
rewind(amdGpuMemoryClockFile);
fflush(amdGpuMemoryClockFile);
if (fscanf(amdGpuMemoryClockFile, "%" PRId64, &value) != 1)
value = 0;
amdgpu.MemClock = value / 1000000;
gpuMemClock = amdgpu.MemClock;
}
pthread_detach(gpuThread);
return NULL;
}

@ -0,0 +1,24 @@
#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);
bool glXMakeCurrent(void*, void*, void*);
void* glXGetProcAddress(const unsigned char*);
void* glXGetProcAddressARB(const unsigned char*);
unsigned int eglSwapBuffers( void*, void* );
void glClipControl(int origin, int depth);
#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
#include "loaders/loader_gl.h"
extern gl_loader gl;
// 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)
{
// 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 (gl.glClipControl)
gl.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 && gl.glClipControl)
gl.glClipControl(last_clip_origin, last_clip_depth_mode);
#endif
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
printf("%s\n", __func__);
// 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";
printf("glsl_version: %d\n", glsl_version);
// Select shaders matching our GLSL versions
const GLchar* vertex_shader = NULL;
const GLchar* fragment_shader = NULL;
if (glsl_version < 130)
{
printf("glsl_version < 130\n");
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
}
else if (glsl_version >= 410)
{
printf("glsl_version >= 410\n");
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
}
else if (glsl_version == 300)
{
printf("glsl_version == 300\n");
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
}
else
{
printf("vertex_shader_glsl_130\n");
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()
{
printf("%s\n", __func__);
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,287 @@
#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 "mesa/util/macros.h"
#include "mesa/util/os_time.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);
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 *current_state;
static bool inited = false;
std::unordered_map<void*, state> g_imgui_states;
uint32_t vendorID;
std::string deviceName;
void imgui_init()
{
if (inited)
return;
inited = true;
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);
}
void imgui_create(void *ctx)
{
if (!ctx)
return;
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();
auto& state = g_imgui_states[ctx];
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();
GLint vp [4]; glGetIntegerv (GL_VIEWPORT, vp);
printf("viewport %d %d %d %d\n", vp[0], vp[1], vp[2], vp[3]);
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;
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);
current_state = &state;
engineName = "OpenGL";
}
void imgui_destroy(void *ctx)
{
if (!ctx)
return;
auto it = g_imgui_states.find(ctx);
if (it != g_imgui_states.end()) {
ImGui::DestroyContext(it->second.imgui_ctx);
g_imgui_states.erase(it);
}
}
void imgui_shutdown()
{
std::cerr << __func__ << std::endl;
ImGui_ImplOpenGL3_Shutdown();
for(auto &p : g_imgui_states)
ImGui::DestroyContext(p.second.imgui_ctx);
g_imgui_states.clear();
}
void imgui_set_context(void *ctx)
{
if (!ctx) {
imgui_shutdown();
current_state = nullptr;
return;
}
std::cerr << __func__ << std::endl;
auto it = g_imgui_states.find(ctx);
if (it != g_imgui_states.end()) {
ImGui::SetCurrentContext(it->second.imgui_ctx);
current_state = &it->second;
} else {
imgui_create(ctx);
}
sw_stats.font1 = current_state->font1;
}
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(2);
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) {
gl.Load();
void *func = gl.glXGetProcAddress( (const unsigned char*) name );
if (!func)
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);
std::cerr << __func__ << ":" << ctx << std::endl;
return ctx;
}
EXPORT_C_(bool) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
gl.Load();
bool ret = gl.glXMakeCurrent(dpy, drawable, ctx);
if (ret)
imgui_set_context(ctx);
std::cerr << __func__ << std::endl;
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();
}
}
struct func_ptr {
const char *name;
void *ptr;
};
static std::array<const func_ptr, 5> 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),
#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 gl.glXGetProcAddress(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 gl.glXGetProcAddressARB(procName);
}
#ifdef HOOK_DLSYM
EXPORT_C_(void*) dlsym(void * handle, const char * name)
{
void* func = find_ptr(name);
if (func) {
//std::cerr << __func__ << ":" << name << std::endl;
return func;
}
//std::cerr << __func__ << ": foreign: " << name << std::endl;
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*);

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

@ -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"));
glXMakeCurrent =
reinterpret_cast<decltype(this->glXMakeCurrent)>(
glXGetProcAddress((const unsigned char *)"glXMakeCurrent"));
if (!glXMakeCurrent) {
CleanUp(true);
return false;
}
glClipControl =
reinterpret_cast<decltype(this->glClipControl)>(
glXGetProcAddress((const unsigned char *)"glClipControl"));
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,39 @@
#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(&::glXMakeCurrent) glXMakeCurrent;
decltype(&::glClipControl) glClipControl;
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

@ -42,14 +42,26 @@ vklayer_files = files(
'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 : [
@ -69,7 +81,7 @@ 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 : true
)
@ -78,3 +90,10 @@ install_data(
files('mangohud.json'),
install_dir : join_paths(get_option('datadir'), 'vulkan', 'implicit_layer.d'),
)
install_data(
files('../bin/run-mangohud-gl-pkg.sh'),
install_dir : get_option('bindir'),
install_mode: 'rwxr-xr-x',
rename : ['run-mangohud-gl.sh']
)

@ -36,7 +36,7 @@
#include "imgui.h"
#include "overlay_params.h"
#include "overlay.h"
#include "font_default.h"
// #include "util/debug.h"
@ -50,12 +50,12 @@
#include "string_utils.h"
#include "file_utils.h"
#include "cpu_gpu.h"
#include "gpu.h"
#include "logging.h"
#include "keybinds.h"
#include "cpu.h"
#include "iostats.h"
#include "loaders/loader_nvml.h"
#include "memory.h"
bool open = false;
string gpuString;
@ -63,7 +63,7 @@ float offset_x, offset_y, hudSpacing;
int hudFirstRow, hudSecondRow;
string engineName, engineVersion;
struct amdGpu amdgpu;
int64_t frameStart, frameEnd, targetFrameTime = 0, frameOverhead = 0, sleepTime = 0;
struct fps_limit fps_limit_stats;
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
@ -84,10 +84,6 @@ struct instance_data {
bool capture_started;
};
struct frame_stat {
uint64_t stats[OVERLAY_PARAM_ENABLED_MAX];
};
/* Mapped from VkDevice */
struct queue_data;
struct device_data {
@ -107,7 +103,6 @@ struct device_data {
/* For a single frame */
struct frame_stat frame_stats;
bool gpu_stats = false;
};
/* Mapped from VkCommandBuffer */
@ -183,7 +178,6 @@ struct swapchain_data {
std::list<overlay_draw *> draws; /* List of struct overlay_draw */
ImFont* font = nullptr;
ImFont* font1 = nullptr;
bool font_uploaded;
VkImage font_image;
VkImageView font_image_view;
@ -196,30 +190,22 @@ struct swapchain_data {
ImVec2 window_size;
/**/
uint64_t n_frames;
uint64_t last_present_time;
unsigned n_frames_since_update;
uint64_t last_fps_update;
double fps;
double frametime;
double frametimeDisplay;
const char* cpuString;
const char* gpuString;
std::string time;
enum overlay_param_enabled stat_selector;
double time_dividor;
struct frame_stat stats_min, stats_max;
struct frame_stat frames_stats[200];
struct swapchain_stats sw_stats;
/* Over a single frame */
struct frame_stat frame_stats;
/* Over fps_sampling_period */
struct frame_stat accumulated_stats;
struct iostats io;
};
static const VkQueryPipelineStatisticFlags overlay_query_flags =
@ -501,8 +487,6 @@ static struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain,
struct swapchain_data *data = new swapchain_data();
data->device = device_data;
data->swapchain = swapchain;
if (instance_data->params.font_size > 0 && instance_data->params.width == 280)
instance_data->params.width = hudFirstRow + hudSecondRow;
data->window_size = ImVec2(instance_data->params.width, instance_data->params.height);
map_object(HKEY(data->swapchain), data);
return data;
@ -771,20 +755,42 @@ static void process_control_socket(struct instance_data *instance_data)
}
}
void init_gpu_stats(struct device_data *device_data)
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 init_gpu_stats(uint32_t& vendorID, overlay_params& params)
{
struct instance_data *instance_data = device_data->instance;
if (!params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats])
return;
// NVIDIA or Intel but maybe has Optimus
if (device_data->properties.vendorID == 0x8086
|| device_data->properties.vendorID == 0x10de) {
if ((device_data->gpu_stats = checkNvidia())) {
device_data->properties.vendorID = 0x10de;
if (vendorID == 0x8086
|| vendorID == 0x10de) {
if ((params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = checkNvidia())) {
vendorID = 0x10de;
}
}
if (device_data->properties.vendorID == 0x8086
|| device_data->properties.vendorID == 0x1002
if (vendorID == 0x8086 || vendorID == 0x1002
|| gpu.find("Radeon") != std::string::npos
|| gpu.find("AMD") != std::string::npos) {
string path;
@ -827,8 +833,8 @@ void init_gpu_stats(struct device_data *device_data)
if (!amdTempFile)
amdTempFile = fopen(path.c_str(), "r");
device_data->gpu_stats = true;
device_data->properties.vendorID = 0x1002;
params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = true;
vendorID = 0x1002;
break;
}
}
@ -836,67 +842,13 @@ void init_gpu_stats(struct device_data *device_data)
// don't bother then
if (!amdGpuFile && !amdTempFile && !amdGpuVramTotalFile && !amdGpuVramUsedFile) {
device_data->gpu_stats = false;
params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = false;
}
}
}
static void snapshot_swapchain_frame(struct swapchain_data *data)
{
struct device_data *device_data = data->device;
struct instance_data *instance_data = device_data->instance;
uint32_t f_idx = data->n_frames % ARRAY_SIZE(data->frames_stats);
uint64_t now = os_time_get(); /* us */
if (instance_data->params.control >= 0) {
control_client_check(device_data);
process_control_socket(instance_data);
}
double elapsed = (double)(now - data->last_fps_update); /* us */
elapsedF2 = (double)(now - last_f2_press);
elapsedF12 = (double)(now - last_f12_press);
elapsedRefreshConfig = (double)(now - refresh_config_press);
fps = 1000000.0f * data->n_frames_since_update / elapsed;
if (data->last_present_time) {
data->frame_stats.stats[OVERLAY_PARAM_ENABLED_frame_timing] =
now - data->last_present_time;
}
memset(&data->frames_stats[f_idx], 0, sizeof(data->frames_stats[f_idx]));
for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
data->frames_stats[f_idx].stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];
data->accumulated_stats.stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];
}
if (elapsedF2 >= 500000 && mangohud_output_env){
if (key_is_pressed(instance_data->params.toggle_logging)){
last_f2_press = now;
log_start = now;
loggingOn = !loggingOn;
if (loggingOn && log_period != 0)
pthread_create(&f2, NULL, &logging, NULL);
}
}
if (elapsedF12 >= 500000){
if (key_is_pressed(instance_data->params.toggle_hud)){
instance_data->params.no_display = !instance_data->params.no_display;
last_f12_press = now;
}
}
if (elapsedRefreshConfig >= 500000){
if (key_is_pressed(instance_data->params.refresh_config)){
parse_overlay_config(&instance_data->params, getenv("MANGOHUD_CONFIG"));
refresh_config_press = now;
}
}
if (!sysInfoFetched) {
void init_system_info(){
unsetenv("LD_PRELOAD");
ram = exec("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'");
trim(ram);
cpu = exec("cat /proc/cpuinfo | grep 'model name' | tail -n1 | sed 's/^.*: //' | sed 's/([^)]*)/()/g' | tr -d '(/)'");
@ -924,141 +876,122 @@ static void snapshot_swapchain_frame(struct swapchain_data *data)
if (!log_period_env || !try_stoi(log_period, log_period_env))
log_period = 100;
if (log_period == 0)
out.open("/tmp/mango", ios::out | ios::app);
if (log_duration_env && !try_stoi(duration, log_duration_env))
duration = 0;
}
string name, path;
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)) {
cerr << "MANGOHUD: Could not find cpu temp sensor location" << endl;
} else {
cpuTempFile = fopen(path.c_str(), "r");
void check_keybinds(struct overlay_params& params){
uint64_t now = os_time_get(); /* us */
elapsedF2 = (double)(now - last_f2_press);
elapsedF12 = (double)(now - last_f12_press);
elapsedRefreshConfig = (double)(now - refresh_config_press);
if (elapsedF2 >= 500000 && mangohud_output_env){
if (key_is_pressed(params.toggle_logging)){
last_f2_press = now;
log_start = now;
loggingOn = !loggingOn;
if (loggingOn && log_period != 0)
pthread_create(&f2, NULL, &logging, NULL);
}
}
if (elapsedF12 >= 500000){
if (key_is_pressed(params.toggle_hud)){
last_f12_press = now;
params.no_display = !params.no_display;
}
}
sysInfoFetched = true;
if (elapsedRefreshConfig >= 500000){
if (key_is_pressed(params.refresh_config)){
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
refresh_config_press = now;
}
}
}
/* If capture has been enabled but it hasn't started yet, it means we are on
* the first snapshot after it has been enabled. At this point we want to
* use the stats captured so far to update the display, but we don't want
* this data to cause noise to the stats that we want to capture from now
* on.
*
* capture_begin == true will trigger an update of the fps on display, and a
* flush of the data, but no stats will be written to the output file. This
* way, we will have only stats from after the capture has been enabled
* written to the output_file.
*/
const bool capture_begin =
instance_data->capture_enabled && !instance_data->capture_started;
void update_hud_info(struct swapchain_stats& sw_stats, struct overlay_params& params, uint32_t vendorID){
uint32_t f_idx = sw_stats.n_frames % ARRAY_SIZE(sw_stats.frames_stats);
uint64_t now = os_time_get(); /* us */
double elapsed = (double)(now - sw_stats.last_fps_update); /* us */
fps = 1000000.0f * sw_stats.n_frames_since_update / elapsed;
if (data->last_fps_update) {
if (capture_begin ||
elapsed >= instance_data->params.fps_sampling_period) {
if (sw_stats.last_present_time) {
sw_stats.frames_stats[f_idx].stats[OVERLAY_PARAM_ENABLED_frame_timing] =
now - sw_stats.last_present_time;
}
if (sw_stats.last_fps_update) {
if (elapsed >= params.fps_sampling_period) {
cpuStats.UpdateCPUData();
cpuLoadLog = cpuStats.GetCPUDataTotal().percent;
if (cpuTempFile)
pthread_create(&cpuInfoThread, NULL, &cpuInfo, NULL);
sw_stats.total_cpu = cpuStats.GetCPUDataTotal().percent;
if (device_data->gpu_stats) {
// get gpu usage
if (device_data->properties.vendorID == 0x10de)
pthread_create(&gpuThread, NULL, &getNvidiaGpuInfo, NULL);
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats]) {
if (vendorID == 0x1002)
pthread_create(&gpuThread, NULL, &getAmdGpuUsage, NULL);
if (device_data->properties.vendorID == 0x1002)
pthread_create(&gpuThread, NULL, &getAmdGpuUsage, NULL);
if (vendorID == 0x10de)
pthread_create(&gpuThread, NULL, &getNvidiaGpuInfo, NULL);
}
// get ram usage/max
pthread_create(&memoryThread, NULL, &update_meminfo, NULL);
pthread_create(&ioThread, NULL, &getIoStats, &data->io);
// update variables for logging
// cpuLoadLog = cpuArray[0].value;
gpuLoadLog = gpuLoad;
pthread_create(&ioThread, NULL, &getIoStats, &sw_stats.io);
data->frametimeDisplay = data->frametime;
data->fps = fps;
gpuLoadLog = gpu_info.load;
cpuLoadLog = sw_stats.total_cpu;
sw_stats.fps = fps;
std::time_t t = std::time(nullptr);
std::stringstream time;
time << std::put_time(std::localtime(&t), instance_data->params.time_format.c_str());
data->time = time.str();
if (instance_data->capture_started) {
if (!instance_data->first_line_printed) {
bool first_column = true;
instance_data->first_line_printed = true;
#define OVERLAY_PARAM_BOOL(name) \
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_##name]) { \
fprintf(instance_data->params.output_file, \
"%s%s%s", first_column ? "" : ", ", #name, \
param_unit(OVERLAY_PARAM_ENABLED_##name)); \
first_column = false; \
}
#define OVERLAY_PARAM_CUSTOM(name)
OVERLAY_PARAMS
#undef OVERLAY_PARAM_BOOL
#undef OVERLAY_PARAM_CUSTOM
fprintf(instance_data->params.output_file, "\n");
}
for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
if (!instance_data->params.enabled[s])
continue;
if (s == OVERLAY_PARAM_ENABLED_fps) {
fprintf(instance_data->params.output_file,
"%s%.2f", s == 0 ? "" : ", ", data->fps);
} else {
fprintf(instance_data->params.output_file,
"%s%" PRIu64, s == 0 ? "" : ", ",
data->accumulated_stats.stats[s]);
}
}
fprintf(instance_data->params.output_file, "\n");
fflush(instance_data->params.output_file);
}
time << std::put_time(std::localtime(&t), params.time_format.c_str());
sw_stats.time = time.str();
memset(&data->accumulated_stats, 0, sizeof(data->accumulated_stats));
data->n_frames_since_update = 0;
data->last_fps_update = now;
sw_stats.n_frames_since_update = 0;
sw_stats.last_fps_update = now;
if (capture_begin)
instance_data->capture_started = true;
}
}
} else {
data->last_fps_update = now;
sw_stats.last_fps_update = now;
}
memset(&device_data->frame_stats, 0, sizeof(device_data->frame_stats));
memset(&data->frame_stats, 0, sizeof(device_data->frame_stats));
// memset(&device_data->frame_stats, 0, sizeof(device_data->frame_stats));
// memset(&data->frame_stats, 0, sizeof(device_data->frame_stats));
sw_stats.last_present_time = now;
sw_stats.n_frames++;
sw_stats.n_frames_since_update++;
}
static void snapshot_swapchain_frame(struct swapchain_data *data)
{
struct device_data *device_data = data->device;
struct instance_data *instance_data = device_data->instance;
update_hud_info(data->sw_stats, instance_data->params, device_data->properties.vendorID);
check_keybinds(instance_data->params);
// not currently used
// if (instance_data->params.control >= 0) {
// control_client_check(device_data);
// process_control_socket(instance_data);
// }
// not currently used
// memset(&data->sw_stats.frames_stats[f_idx], 0, sizeof(data->sw_stats.frames_stats[f_idx]));
// for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
// data->sw_stats.frames_stats[f_idx].stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];
// data->accumulated_stats.stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];
// }
data->last_present_time = now;
data->n_frames++;
data->n_frames_since_update++;
}
static float get_time_stat(void *_data, int _idx)
{
struct swapchain_data *data = (struct swapchain_data *) _data;
struct swapchain_stats *data = (struct swapchain_stats *) _data;
if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames)
return 0.0f;
int idx = ARRAY_SIZE(data->frames_stats) +
@ -1070,35 +1003,32 @@ static float get_time_stat(void *_data, int _idx)
return data->frames_stats[idx].stats[data->stat_selector] / data->time_dividor;
}
static void position_layer(struct swapchain_data *data)
void position_layer(struct overlay_params& params, ImVec2 window_size, unsigned width, unsigned height)
{
struct device_data *device_data = data->device;
struct instance_data *instance_data = device_data->instance;
float margin = 10.0f;
if (instance_data->params.offset_x > 0 || instance_data->params.offset_y > 0)
if (params.offset_x > 0 || params.offset_y > 0)
margin = 0.0f;
ImGui::SetNextWindowBgAlpha(instance_data->params.background_alpha);
ImGui::SetNextWindowSize(data->window_size, ImGuiCond_Always);
ImGui::SetNextWindowBgAlpha(params.background_alpha);
ImGui::SetNextWindowSize(window_size, ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8,-3));
switch (instance_data->params.position) {
switch (params.position) {
case LAYER_POSITION_TOP_LEFT:
ImGui::SetNextWindowPos(ImVec2(margin + instance_data->params.offset_x, margin + instance_data->params.offset_y), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(margin + params.offset_x, margin + params.offset_y), ImGuiCond_Always);
break;
case LAYER_POSITION_TOP_RIGHT:
ImGui::SetNextWindowPos(ImVec2(data->width - data->window_size.x - margin + instance_data->params.offset_x, margin + instance_data->params.offset_y),
ImGui::SetNextWindowPos(ImVec2(width - window_size.x - margin + params.offset_x, margin + params.offset_y),
ImGuiCond_Always);
break;
case LAYER_POSITION_BOTTOM_LEFT:
ImGui::SetNextWindowPos(ImVec2(margin + instance_data->params.offset_x, data->height - data->window_size.y - margin + instance_data->params.offset_y),
ImGui::SetNextWindowPos(ImVec2(margin + params.offset_x, height - window_size.y - margin + params.offset_y),
ImGuiCond_Always);
break;
case LAYER_POSITION_BOTTOM_RIGHT:
ImGui::SetNextWindowPos(ImVec2(data->width - data->window_size.x - margin + instance_data->params.offset_x,
data->height - data->window_size.y - margin + instance_data->params.offset_y),
ImGui::SetNextWindowPos(ImVec2(width - window_size.x - margin + params.offset_x,
height - window_size.y - margin + params.offset_y),
ImGuiCond_Always);
break;
}
@ -1119,74 +1049,68 @@ static void right_aligned_text(float off_x, const char *fmt, ...)
ImGui::Text("%s", buffer);
}
static void compute_swapchain_display(struct swapchain_data *data)
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, unsigned width, unsigned height)
{
struct device_data *device_data = data->device;
struct instance_data *instance_data = device_data->instance;
ImGui::SetCurrentContext(data->imgui_context);
ImGui::NewFrame();
position_layer(data);
static float char_width = ImGui::CalcTextSize("A").x;
if (!instance_data->params.no_display){
if (!params.no_display){
ImGui::Begin("Main", &open, ImGuiWindowFlags_NoDecoration);
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_time]){
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.00f), "%s", data->time.c_str());
ImGui::BeginTable("hud", params.tableCols);
if (params.enabled[OVERLAY_PARAM_ENABLED_time]){
ImGui::TableNextRow();
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.00f), "%s", data.time.c_str());
}
ImGui::BeginTable("hud", instance_data->params.tableCols);
if (device_data->gpu_stats && instance_data->params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats]){
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats]){
ImGui::TableNextRow();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.gpu_color), "GPU");
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.gpu_color), "GPU");
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", gpuLoad);
right_aligned_text(char_width * 4, "%i", gpu_info.load);
ImGui::SameLine(0, 1.0f);
ImGui::Text("%%");
// ImGui::SameLine(150);
// ImGui::Text("%s", "%");
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_gpu_temp]){
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_temp]){
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", gpuTemp);
right_aligned_text(char_width * 4, "%i", gpu_info.temp);
ImGui::SameLine(0, 1.0f);
ImGui::Text("°C");
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock]){
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock]){
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", gpuCoreClock);
right_aligned_text(char_width * 4, "%i", gpu_info.CoreClock);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("MHz");
ImGui::PopFont();
}
}
if(instance_data->params.enabled[OVERLAY_PARAM_ENABLED_cpu_stats]){
if(params.enabled[OVERLAY_PARAM_ENABLED_cpu_stats]){
ImGui::TableNextRow();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.cpu_color), "CPU");
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.cpu_color), "CPU");
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%d", cpuLoadLog);
right_aligned_text(char_width * 4, "%d", data.total_cpu);
ImGui::SameLine(0, 1.0f);
ImGui::Text("%%");
// ImGui::SameLine(150);
// ImGui::Text("%s", "%");
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_cpu_temp]){
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_temp]){
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", cpuTemp);
right_aligned_text(char_width * 4, "%i", cpuStats.GetCPUDataTotal().temp);
ImGui::SameLine(0, 1.0f);
ImGui::Text("°C");
}
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_core_load]){
if (params.enabled[OVERLAY_PARAM_ENABLED_core_load]){
int i = 0;
for (const CPUData &cpuData : cpuStats.GetCPUData())
{
ImGui::TableNextRow();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.cpu_color), "CPU");
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.cpu_color), "CPU");
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(data->font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.cpu_color),"%i", i);
ImGui::PushFont(data.font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.cpu_color),"%i", i);
ImGui::PopFont();
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", int(cpuData.percent));
@ -1195,88 +1119,88 @@ static void compute_swapchain_display(struct swapchain_data *data)
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", cpuData.mhz);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("MHz");
ImGui::PopFont();
i++;
}
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_read] || instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_write]){
auto sampling = instance_data->params.fps_sampling_period;
if (params.enabled[OVERLAY_PARAM_ENABLED_io_read] || params.enabled[OVERLAY_PARAM_ENABLED_io_write]){
auto sampling = params.fps_sampling_period;
ImGui::TableNextRow();
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_read] && !instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_write])
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.io_color), "IO RD");
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_write] && !instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_read])
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.io_color), "IO RW");
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_read] && instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_write])
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.io_color), "IO RD/RW");
if (params.enabled[OVERLAY_PARAM_ENABLED_io_read] && !params.enabled[OVERLAY_PARAM_ENABLED_io_write])
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.io_color), "IO RD");
if (params.enabled[OVERLAY_PARAM_ENABLED_io_write] && !params.enabled[OVERLAY_PARAM_ENABLED_io_read])
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.io_color), "IO RW");
if (params.enabled[OVERLAY_PARAM_ENABLED_io_read] && params.enabled[OVERLAY_PARAM_ENABLED_io_write])
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.io_color), "IO RD/RW");
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_read]){
if (params.enabled[OVERLAY_PARAM_ENABLED_io_read]){
ImGui::TableNextCell();
float val = data->io.diff.read * (1000000 / sampling);
float val = data.io.diff.read * (1000000 / sampling);
right_aligned_text(char_width * 4, val < 100 ? "%.2f" : "%.f", val);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("MiB/s");
ImGui::PopFont();
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_io_write]){
if (params.enabled[OVERLAY_PARAM_ENABLED_io_write]){
ImGui::TableNextCell();
float val = data->io.diff.write * (1000000 / sampling);
float val = data.io.diff.write * (1000000 / sampling);
right_aligned_text(char_width * 4, val < 100 ? "%.2f" : "%.f", val);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("MiB/s");
ImGui::PopFont();
}
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_vram]){
if (params.enabled[OVERLAY_PARAM_ENABLED_vram]){
ImGui::TableNextRow();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.vram_color), "VRAM");
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.vram_color), "VRAM");
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%.2f", gpuMemUsed);
right_aligned_text(char_width * 4, "%.2f", gpu_info.memoryUsed);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("GB");
ImGui::PopFont();
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock]){
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock]){
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%i", gpuMemClock);
right_aligned_text(char_width * 4, "%i", gpu_info.MemClock);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("MHz");
ImGui::PopFont();
}
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_ram]){
if (params.enabled[OVERLAY_PARAM_ENABLED_ram]){
ImGui::TableNextRow();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.ram_color), "RAM");
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.ram_color), "RAM");
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%.2f", memused);
ImGui::SameLine(0,1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("GB");
ImGui::PopFont();
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_fps]){
if (params.enabled[OVERLAY_PARAM_ENABLED_fps]){
ImGui::TableNextRow();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.engine_color), "%s", engineName.c_str());
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.engine_color), "%s", engineName.c_str());
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%.0f", data->fps);
right_aligned_text(char_width * 4, "%.0f", data.fps);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("FPS");
ImGui::PopFont();
ImGui::TableNextCell();
right_aligned_text(char_width * 4, "%.1f", 1000 / data->fps);
right_aligned_text(char_width * 4, "%.1f", 1000 / data.fps);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(data->font1);
ImGui::PushFont(data.font1);
ImGui::Text("ms");
ImGui::PopFont();
if (engineName == "DXVK" || engineName == "VKD3D"){
ImGui::TableNextRow();
ImGui::PushFont(data->font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.engine_color), "%s", engineVersion.c_str());
ImGui::PushFont(data.font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.engine_color), "%s", engineVersion.c_str());
ImGui::PopFont();
}
}
@ -1290,50 +1214,49 @@ static void compute_swapchain_display(struct swapchain_data *data)
out << fps << "," << cpuLoadLog << "," << gpuLoadLog << "," << (now - log_start) << endl;
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_frame_timing]){
ImGui::Dummy(ImVec2(0.0f, instance_data->params.font_size / 2));
ImGui::PushFont(data->font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(instance_data->params.engine_color), "%s", "Frametime");
if (params.enabled[OVERLAY_PARAM_ENABLED_frame_timing]){
ImGui::Dummy(ImVec2(0.0f, params.font_size / 2));
ImGui::PushFont(data.font1);
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(params.engine_color), "%s", "Frametime");
ImGui::PopFont();
}
for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
if (!instance_data->params.enabled[s] ||
if (!params.enabled[s] ||
s == OVERLAY_PARAM_ENABLED_fps ||
s == OVERLAY_PARAM_ENABLED_frame)
continue;
char hash[40];
snprintf(hash, sizeof(hash), "##%s", overlay_param_names[s]);
data->stat_selector = (enum overlay_param_enabled) s;
data->time_dividor = 1000.0f;
data.stat_selector = (enum overlay_param_enabled) s;
data.time_dividor = 1000.0f;
if (s == OVERLAY_PARAM_ENABLED_gpu_timing)
data->time_dividor = 1000000.0f;
data.time_dividor = 1000000.0f;
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
if (s == OVERLAY_PARAM_ENABLED_frame_timing) {
double min_time = 0.0f;
double max_time = 50.0f;
ImGui::PlotLines(hash, get_time_stat, data,
ARRAY_SIZE(data->frames_stats), 0,
ImGui::PlotLines(hash, get_time_stat, &data,
ARRAY_SIZE(data.frames_stats), 0,
NULL, min_time, max_time,
ImVec2(ImGui::GetContentRegionAvailWidth() - instance_data->params.font_size * 2.2, 50));
ImVec2(ImGui::GetContentRegionAvailWidth() - params.font_size * 2.2, 50));
}
ImGui::PopStyleColor();
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_frame_timing]){
if (params.enabled[OVERLAY_PARAM_ENABLED_frame_timing]){
ImGui::SameLine(0,1.0f);
ImGui::PushFont(data->font1);
ImGui::Text("%.1f ms", 1000 / data->fps);
ImGui::PushFont(data.font1);
ImGui::Text("%.1f ms", 1000 / data.fps);
ImGui::PopFont();
}
data->window_size = ImVec2(data->window_size.x, ImGui::GetCursorPosY() + 10.0f);
window_size = ImVec2(window_size.x, ImGui::GetCursorPosY() + 10.0f);
ImGui::End();
}
if(loggingOn){
ImGui::SetNextWindowBgAlpha(0.0);
ImGui::SetNextWindowSize(ImVec2(instance_data->params.font_size * 13, instance_data->params.font_size * 13), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(data->width - instance_data->params.font_size * 13,
ImGui::SetNextWindowSize(ImVec2(params.font_size * 13, params.font_size * 13), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(width - params.font_size * 13,
0),
ImGuiCond_Always);
ImGui::Begin("Logging", &open, ImGuiWindowFlags_NoDecoration);
@ -1341,24 +1264,37 @@ static void compute_swapchain_display(struct swapchain_data *data)
ImGui::Text("Elapsed: %isec", int((elapsedLog) / 1000000));
ImGui::End();
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_crosshair]){
if (params.enabled[OVERLAY_PARAM_ENABLED_crosshair]){
ImGui::SetNextWindowBgAlpha(0.0);
ImGui::SetNextWindowSize(ImVec2(data->width, data->height), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::Begin("Logging", &open, ImGuiWindowFlags_NoDecoration);
ImVec2 horiz = ImVec2(data->width / 2 - (instance_data->params.crosshair_size / 2), data->height / 2);
ImVec2 vert = ImVec2(data->width / 2, data->height / 2 - (instance_data->params.crosshair_size / 2));
ImVec2 horiz = ImVec2(width / 2 - (params.crosshair_size / 2), height / 2);
ImVec2 vert = ImVec2(width / 2, height / 2 - (params.crosshair_size / 2));
ImGui::GetWindowDrawList()->AddLine(horiz,
ImVec2(horiz.x + instance_data->params.crosshair_size, horiz.y + 0),
instance_data->params.crosshair_color, 2.0f);
ImVec2(horiz.x + params.crosshair_size, horiz.y + 0),
params.crosshair_color, 2.0f);
ImGui::GetWindowDrawList()->AddLine(vert,
ImVec2(vert.x + 0, vert.y + instance_data->params.crosshair_size),
instance_data->params.crosshair_color, 2.0f);
ImVec2(vert.x + 0, vert.y + params.crosshair_size),
params.crosshair_color, 2.0f);
ImGui::End();
}
ImGui::PopStyleVar(2);
ImGui::EndFrame();
ImGui::Render();
}
static void compute_swapchain_display(struct swapchain_data *data)
{
struct device_data *device_data = data->device;
struct instance_data *instance_data = device_data->instance;
ImGui::SetCurrentContext(data->imgui_context);
ImGui::NewFrame();
position_layer(instance_data->params, data->window_size, data->width, data->height);
render_imgui(data->sw_stats, instance_data->params, data->window_size, data->width, data->height);
ImGui::PopStyleVar(2);
ImGui::EndFrame();
ImGui::Render();
}
static uint32_t vk_memory_type(struct device_data *data,
@ -1937,14 +1873,14 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data)
// ImGui takes ownership of the data, no need to free it
if (mangohud_font && file_exists(mangohud_font)) {
data->font = io.Fonts->AddFontFromFileTTF(mangohud_font, font_size);
data->font1 = io.Fonts->AddFontFromFileTTF(mangohud_font, font_size * 0.55f);
data->sw_stats.font1 = io.Fonts->AddFontFromFileTTF(mangohud_font, font_size * 0.55f);
} else {
ImFontConfig font_cfg = ImFontConfig();
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
const ImWchar* glyph_ranges = io.Fonts->GetGlyphRangesDefault();
data->font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, &font_cfg, glyph_ranges);
data->font1 = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55, &font_cfg, glyph_ranges);
data->sw_stats.font1 = io.Fonts->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55, &font_cfg, glyph_ranges);
}
unsigned char* pixels;
int width, height;
@ -2007,6 +1943,12 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data)
write_desc[0].pImageInfo = desc_image;
device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL);
}
void imgui_custom_style(){
ImGuiStyle& style = ImGui::GetStyle();
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.0f, 1.0f, 0.0f, 1.00f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.0f);
style.CellPadding.y = -2;
}
static void setup_swapchain_data(struct swapchain_data *data,
const VkSwapchainCreateInfoKHR *pCreateInfo)
@ -2020,12 +1962,7 @@ static void setup_swapchain_data(struct swapchain_data *data,
ImGui::GetIO().IniFilename = NULL;
ImGui::GetIO().DisplaySize = ImVec2((float)data->width, (float)data->height);
ImGuiStyle& style = ImGui::GetStyle();
//style.Colors[ImGuiCol_FrameBg] = ImVec4(0.0f, 0.0f, 0.0f, 0.00f); // Setting temporarily with PushStyleColor()
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.0f, 1.0f, 0.0f, 1.00f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.0f);
style.CellPadding.y = -2;
imgui_custom_style();
struct device_data *device_data = data->device;
@ -2184,7 +2121,7 @@ static struct overlay_draw *before_present(struct swapchain_data *swapchain_data
snapshot_swapchain_frame(swapchain_data);
if (swapchain_data->n_frames > 0) {
if (swapchain_data->sw_stats.n_frames > 0) {
compute_swapchain_display(swapchain_data);
draw = render_swapchain_display(swapchain_data, present_queue,
wait_semaphores, n_wait_semaphores,
@ -2230,14 +2167,14 @@ static void overlay_DestroySwapchainKHR(
destroy_swapchain_data(swapchain_data);
}
void FpsLimiter(){
sleepTime = targetFrameTime - (frameStart - frameEnd);
if ( sleepTime > frameOverhead ) {
int64_t adjustedSleep = sleepTime - frameOverhead;
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));
frameOverhead = ((os_time_get_nano() - frameStart) - adjustedSleep);
if (frameOverhead > targetFrameTime)
frameOverhead = 0;
stats.frameOverhead = ((os_time_get_nano() - stats.frameStart) - adjustedSleep);
if (stats.frameOverhead > stats.targetFrameTime)
stats.frameOverhead = 0;
}
}
@ -2326,10 +2263,10 @@ static VkResult overlay_QueuePresentKHR(
result = chain_result;
}
if (targetFrameTime > 0){
frameStart = os_time_get_nano();
FpsLimiter();
frameEnd = os_time_get_nano();
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();
}
return result;
@ -2605,7 +2542,8 @@ static VkResult overlay_CreateDevice(
device_map_queues(device_data, pCreateInfo);
init_gpu_stats(device_data);
init_gpu_stats(device_data->properties.vendorID, instance_data->params);
init_system_info();
return result;
}
@ -2668,15 +2606,7 @@ static VkResult overlay_CreateInstance(
parse_overlay_config(&instance_data->params, getenv("MANGOHUD_CONFIG"));
if (instance_data->params.fps_limit > 0)
targetFrameTime = int64_t(1000000000.0 / instance_data->params.fps_limit);
int font_size;
instance_data->params.font_size > 0 ? font_size = instance_data->params.font_size : font_size = 24;
instance_data->params.font_size > 0 ? font_size = instance_data->params.font_size : instance_data->params.font_size = 24;
hudSpacing = font_size / 2;
hudFirstRow = font_size * 4.2;
hudSecondRow = font_size * 7.5;
fps_limit_stats.targetFrameTime = int64_t(1000000000.0 / instance_data->params.fps_limit);
// Adjust height for DXVK/VKD3D version number
if (engineName == "DXVK" || engineName == "VKD3D"){

@ -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(void);

@ -376,9 +376,12 @@ parse_overlay_config(struct overlay_params *params,
}
params->tableCols = 3;
if (!params->font_size)
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;

Loading…
Cancel
Save