Generalize control over socket so it works with OpenGL too

pull/781/head
jackun 2 years ago
parent 6a010d8eab
commit f680c28f1f
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

@ -198,6 +198,11 @@ frame_timing
### Blacklist
# blacklist=
### Control over socket
### Enable and set socket name, '%p' is replaced with process id
# control = mangohud
# control = mangohud-%p
################ WORKAROUNDS #################
### Options starting with "gl_*" are for OpenGL
### Specify what to use for getting display size. Options are "viewport", "scissorbox" or disabled. Defaults to using glXQueryDrawable

@ -10,9 +10,9 @@ import argparse
TIMEOUT = 1.0 # seconds
VERSION_HEADER = bytearray('MesaOverlayControlVersion', 'utf-8')
VERSION_HEADER = bytearray('MangoHudControlVersion', 'utf-8')
DEVICE_NAME_HEADER = bytearray('DeviceName', 'utf-8')
MESA_VERSION_HEADER = bytearray('MesaVersion', 'utf-8')
MANGOHUD_VERSION_HEADER = bytearray('MangoHudVersion', 'utf-8')
DEFAULT_SERVER_ADDRESS = "\0mangohud"
@ -160,21 +160,36 @@ def control(args):
version = None
name = None
mesa_version = None
mangohud_version = None
msgs = msgparser.readCmd(3)
for m in msgs:
cmd, param = m
if cmd == VERSION_HEADER:
version = int(param)
elif cmd == DEVICE_NAME_HEADER:
name = param.decode('utf-8')
elif cmd == MANGOHUD_VERSION_HEADER:
mangohud_version = param.decode('utf-8')
if args.info:
info = "Protocol Version: {}\n"
info += "Device Name: {}\n"
info += "Mesa Version: {}"
print(info.format(version, name, mesa_version))
info += "MangoHud Version: {}"
print(info.format(version, name, mangohud_version))
if args.cmd == 'toggle-logging':
conn.send(bytearray(':logging;', 'utf-8'))
elif args.cmd == 'start-logging':
conn.send(bytearray(':logging=1;', 'utf-8'))
elif args.cmd == 'stop-logging':
conn.send(bytearray(':logging=0;', 'utf-8'))
elif args.cmd == 'toggle-hud':
conn.send(bytearray(':hud;', 'utf-8'))
elif args.cmd == 'toggle-fcat':
conn.send(bytearray(':fcat;', 'utf-8'))
def main():
parser = argparse.ArgumentParser(description='MangoHud control client')
@ -184,10 +199,13 @@ def main():
commands = parser.add_subparsers(help='commands to run', dest='cmd')
commands.add_parser('toggle-hud')
commands.add_parser('toggle-logging')
commands.add_parser('start-logging')
commands.add_parser('stop-logging')
commands.add_parser('toggle-fcat')
args = parser.parse_args()
control(args)
if __name__ == '__main__':
main()
main()

@ -1,14 +1,18 @@
#include <mutex>
#include <list>
#include <fstream>
#include <unordered_map>
#include <sys/stat.h>
#include <unistd.h>
#include "overlay.h"
#include <inttypes.h>
#include "mesa/util/macros.h"
#include "vk_enum_to_str.h"
#include <vulkan/vk_layer.h>
#include <vulkan/vk_util.h>
#include "nlohmann/json.hpp"
#include "engine_types.h"
using namespace std;
using json = nlohmann::json;
// single global lock, for simplicity
@ -16,6 +20,14 @@ std::mutex global_lock;
typedef std::lock_guard<std::mutex> scoped_lock;
std::unordered_map<uint64_t, void *> vk_object_to_data;
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
struct vk_instance_dispatch_table vtable;
VkInstance instance;
string engineName, engineVersion;
enum EngineTypes engine;
};
#define HKEY(obj) ((uint64_t)(obj))
#define FIND(type, obj) (reinterpret_cast<type *>(find_object_data(HKEY(obj))))
@ -53,8 +65,6 @@ static struct instance_data *new_instance_data(VkInstance instance)
{
struct instance_data *data = new instance_data();
data->instance = instance;
data->params = {};
data->params.control = -1;
map_object(HKEY(data->instance), data);
return data;
}
@ -147,7 +157,7 @@ static VkResult overlay_CreateInstance(
struct stat info;
string path = "/tmp/mangoapp/";
string command = "mkdir -p " + path;
string json_path = path + to_string(getpid()) + ".json";
string json_path = path + to_string(getpid()) + ".json";
if( stat(path.c_str(), &info ) != 0 )
system(command.c_str());
json j;

@ -10,6 +10,7 @@
#include <thread>
#include <unistd.h>
#include "../overlay.h"
#include "notify.h"
#include "mangoapp.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
@ -20,6 +21,7 @@
#include "nlohmann/json.hpp"
using json = nlohmann::json;
using namespace std;
static void glfw_error_callback(int error, const char* description)
{
@ -27,7 +29,7 @@ static void glfw_error_callback(int error, const char* description)
}
swapchain_stats sw_stats {};
overlay_params *params;
overlay_params params {};
static ImVec2 window_size;
static uint32_t vendorID;
static std::string deviceName;
@ -97,13 +99,13 @@ static void ctrl_thread(){
// Keep as-is
break;
case 1:
params->no_display = 1;
params.no_display = 1;
break;
case 2:
params->no_display = 0;
params.no_display = 0;
break;
case 3:
params->no_display ? params->no_display = 0 : params->no_display = 1;
params.no_display ? params.no_display = 0 : params.no_display = 1;
break;
}
}
@ -143,13 +145,13 @@ static void msg_read_thread(){
size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0) + sizeof(long);
if (hdr->version == 1){
if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){
update_hud_info_with_frametime(sw_stats, *params, vendorID, mangoapp_v1->visible_frametime_ns);
update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns);
if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){
g_fsrUpscale = mangoapp_v1->fsrUpscale;
if (params->fsr_steam_sharpness < 0)
if (params.fsr_steam_sharpness < 0)
g_fsrSharpness = mangoapp_v1->fsrSharpness;
else
g_fsrSharpness = params->fsr_steam_sharpness - mangoapp_v1->fsrSharpness;
g_fsrSharpness = params.fsr_steam_sharpness - mangoapp_v1->fsrSharpness;
}
if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam]){
steam_focused = get_prop("GAMESCOPE_FOCUSED_APP_GFX") == 769;
@ -221,9 +223,9 @@ static bool render(GLFWwindow* window) {
ImGui_ImplGlfw_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
overlay_new_frame(*params);
position_layer(sw_stats, *params, window_size);
render_imgui(sw_stats, *params, window_size, true);
overlay_new_frame(params);
position_layer(sw_stats, params, window_size);
render_imgui(sw_stats, params, window_size, true);
overlay_end_frame();
glfwSetWindowSize(window, window_size.x + 45.f, window_size.y + 325.f);
ImGui::EndFrame();
@ -257,18 +259,15 @@ int main(int, char**)
}
// Setup Platform/Renderer backends
struct device_data *device_data = new struct device_data();
device_data->instance = new struct instance_data();
device_data->instance->params = {};
params = &device_data->instance->params;
parse_overlay_config(params, getenv("MANGOHUD_CONFIG"));
create_fonts(*params, sw_stats.font1, sw_stats.font_text);
HUDElements.convert_colors(*params);
init_cpu_stats(*params);
notifier.params = params;
int control_client = -1;
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
create_fonts(params, sw_stats.font1, sw_stats.font_text);
HUDElements.convert_colors(params);
init_cpu_stats(params);
notifier.params = &params;
start_notifier(notifier);
window_size = ImVec2(params->width, params->height);
deviceName = (char*)glGetString(GL_RENDERER);
window_size = ImVec2(params.width, params.height);
deviceName = (char*)glGetString(GL_RENDERER);
sw_stats.deviceName = deviceName;
if (deviceName.find("Radeon") != std::string::npos
|| deviceName.find("AMD") != std::string::npos){
@ -276,7 +275,7 @@ int main(int, char**)
} else {
vendorID = 0x10de;
}
init_gpu_stats(vendorID, 0, *params);
init_gpu_stats(vendorID, 0, params);
init_system_info();
sw_stats.engine = EngineTypes::GAMESCOPE;
std::thread(msg_read_thread).detach();
@ -284,18 +283,18 @@ int main(int, char**)
if(!logger) logger = std::make_unique<Logger>(HUDElements.params);
// Main loop
while (!glfwWindowShouldClose(window)){
if (!params->no_display){
if (!params.no_display){
if (mangoapp_paused){
glfwRestoreWindow(window);
mangoapp_paused = false;
}
{
std::unique_lock<std::mutex> lk(mangoapp_m);
mangoapp_cv.wait(lk, []{return new_frame || params->no_display;});
mangoapp_cv.wait(lk, []{return new_frame || params.no_display;});
new_frame = false;
}
check_keybinds(*params, vendorID);
check_keybinds(params, vendorID);
// Start the Dear ImGui frame
{
if (render(window)) {
@ -306,9 +305,9 @@ int main(int, char**)
render(window);
}
if (params->control >= 0) {
control_client_check(device_data);
process_control_socket(device_data->instance);
if (params.control >= 0) {
control_client_check(params.control, control_client, deviceName);
process_control_socket(control_client, params);
}
}
// Rendering
@ -325,7 +324,7 @@ int main(int, char**)
glfwIconifyWindow(window);
mangoapp_paused = true;
std::unique_lock<std::mutex> lk(mangoapp_m);
mangoapp_cv.wait(lk, []{return !params->no_display;});
mangoapp_cv.wait(lk, []{return !params.no_display;});
}
}

@ -1,35 +1,48 @@
#include <assert.h>
#include <cerrno>
#include <cstring>
#include <sys/socket.h>
#include "mesa/util/os_socket.h"
#include "overlay.h"
#include "version.h"
#ifdef MANGOAPP
#include "app/mangoapp.h"
#endif
using namespace std;
static void parse_command(struct instance_data *instance_data,
static void parse_command(overlay_params &params,
const char *cmd, unsigned cmdlen,
const char *param, unsigned paramlen)
{
if (!strncmp(cmd, "hud", cmdlen)) {
if (!strncmp(cmd, "hud", cmdlen)) {
#ifdef MANGOAPP
{
std::lock_guard<std::mutex> lk(mangoapp_m);
instance_data->params.no_display = !instance_data->params.no_display;
params.no_display = !params.no_display;
}
mangoapp_cv.notify_one();
#else
instance_data->params.no_display = !instance_data->params.no_display;
params.no_display = !params.no_display;
#endif
}
if (!strncmp(cmd, "logging", cmdlen)) {
if (logger->is_active())
logger->stop_logging();
} else if (!strncmp(cmd, "logging", cmdlen)) {
if (param && param[0])
{
int value = atoi(param);
if (!value && logger->is_active())
logger->stop_logging();
else if (value > 0 && !logger->is_active())
logger->start_logging();
}
else
logger->start_logging();
}
{
if (logger->is_active())
logger->stop_logging();
else
logger->start_logging();
}
} else if (!strncmp(cmd, "fcat", cmdlen)) {
params.enabled[OVERLAY_PARAM_ENABLED_fcat] = !params.enabled[OVERLAY_PARAM_ENABLED_fcat];
}
}
#define BUFSIZE 4096
@ -43,7 +56,7 @@ static void parse_command(struct instance_data *instance_data,
*
* :cmd=param;
*/
static void process_char(struct instance_data *instance_data, char c)
static void process_char(const int control_client, overlay_params &params, char c)
{
static char cmd[BUFSIZE];
static char param[BUFSIZE];
@ -65,7 +78,7 @@ static void process_char(struct instance_data *instance_data, char c)
break;
cmd[cmdpos++] = '\0';
param[parampos++] = '\0';
parse_command(instance_data, cmd, cmdpos, param, parampos);
parse_command(params, cmd, cmdpos, param, parampos);
reading_cmd = false;
reading_param = false;
break;
@ -99,7 +112,7 @@ static void process_char(struct instance_data *instance_data, char c)
}
}
static void control_send(struct instance_data *instance_data,
static void control_send(int control_client,
const char *cmd, unsigned cmdlen,
const char *param, unsigned paramlen)
{
@ -120,42 +133,37 @@ static void control_send(struct instance_data *instance_data,
buffer[msglen++] = ';';
}
os_socket_send(instance_data->control_client, buffer, msglen, 0);
os_socket_send(control_client, buffer, msglen, MSG_NOSIGNAL);
}
static void control_send_connection_string(struct device_data *device_data)
static void control_send_connection_string(int control_client, const std::string& deviceName)
{
struct instance_data *instance_data = device_data->instance;
const char *controlVersionCmd = "MesaOverlayControlVersion";
const char *controlVersionCmd = "MangoHudControlVersion";
const char *controlVersionString = "1";
control_send(instance_data, controlVersionCmd, strlen(controlVersionCmd),
control_send(control_client, controlVersionCmd, strlen(controlVersionCmd),
controlVersionString, strlen(controlVersionString));
const char *deviceCmd = "DeviceName";
const char *deviceName = device_data->properties.deviceName;
control_send(instance_data, deviceCmd, strlen(deviceCmd),
deviceName, strlen(deviceName));
control_send(control_client, deviceCmd, strlen(deviceCmd),
deviceName.c_str(), deviceName.size());
const char *mesaVersionCmd = "MesaVersion";
const char *mesaVersionString = "Mesa";
const char *versionCmd = "MangoHudVersion";
const char *versionString = "MangoHud " MANGOHUD_VERSION;
control_send(instance_data, mesaVersionCmd, strlen(mesaVersionCmd),
mesaVersionString, strlen(mesaVersionString));
control_send(control_client, versionCmd, strlen(versionCmd),
versionString, strlen(versionString));
}
void control_client_check(struct device_data *device_data)
void control_client_check(int control, int& control_client, const std::string& deviceName)
{
struct instance_data *instance_data = device_data->instance;
/* Already connected, just return. */
if (instance_data->control_client >= 0)
if (control_client >= 0)
return;
int socket = os_socket_accept(instance_data->params.control);
int socket = os_socket_accept(control);
if (socket == -1) {
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED)
fprintf(stderr, "ERROR on socket: %s\n", strerror(errno));
@ -164,25 +172,24 @@ void control_client_check(struct device_data *device_data)
if (socket >= 0) {
os_socket_block(socket, false);
instance_data->control_client = socket;
control_send_connection_string(device_data);
control_client = socket;
control_send_connection_string(control_client, deviceName);
}
}
static void control_client_disconnected(struct instance_data *instance_data)
static void control_client_disconnected(int& control_client)
{
os_socket_close(instance_data->control_client);
instance_data->control_client = -1;
os_socket_close(control_client);
control_client = -1;
}
void process_control_socket(struct instance_data *instance_data)
void process_control_socket(int& control_client, overlay_params &params)
{
const int client = instance_data->control_client;
if (client >= 0) {
if (control_client >= 0) {
char buf[BUFSIZE];
while (true) {
ssize_t n = os_socket_recv(client, buf, BUFSIZE, 0);
ssize_t n = os_socket_recv(control_client, buf, BUFSIZE, 0);
if (n == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
@ -193,14 +200,14 @@ void process_control_socket(struct instance_data *instance_data)
if (errno != ECONNRESET)
fprintf(stderr, "ERROR on connection: %s\n", strerror(errno));
control_client_disconnected(instance_data);
control_client_disconnected(control_client);
} else if (n == 0) {
/* recv() returns 0 when the client disconnects */
control_client_disconnected(instance_data);
control_client_disconnected(control_client);
}
for (ssize_t i = 0; i < n; i++) {
process_char(instance_data, buf[i]);
process_char(control_client, params, buf[i]);
}
/* If we try to read BUFSIZE and receive BUFSIZE bytes from the

@ -0,0 +1,21 @@
#pragma once
enum EngineTypes
{
UNKNOWN,
OPENGL,
VULKAN,
DXVK,
VKD3D,
DAMAVAND,
ZINK,
WINED3D,
FERAL3D,
TOGL,
GAMESCOPE
};
extern const char* engines[];

@ -191,6 +191,12 @@ void imgui_render(unsigned int width, unsigned int height)
if (!state.imgui_ctx)
return;
static int control_client = -1;
if (params.control >= 0) {
control_client_check(params.control, control_client, deviceName);
process_control_socket(control_client, params);
}
check_keybinds(params, vendorID);
update_hud_info(sw_stats, params, vendorID);

@ -21,6 +21,8 @@
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
using namespace std;
// Cut from https://github.com/ocornut/imgui/pull/2943
// Probably move to ImGui
float SRGBToLinear(float in)

@ -7,6 +7,8 @@
#include "file_utils.h"
#include "string_utils.h"
using namespace std;
string os, cpu, gpu, ram, kernel, driver, cpusched;
bool sysInfoFetched = false;
double fps;
@ -171,7 +173,7 @@ void Logger::stop_logging() {
std::string program = get_wine_exe_name();
if (program.empty())
program = get_program_name();
m_log_files.emplace_back(HUDElements.params->output_folder + "/" + program + "_" + get_log_suffix());
std::thread writefile (writeFile, m_log_files.back());
std::thread writesummary (writeSummary, m_log_files.back());

@ -13,7 +13,6 @@
#include "overlay_params.h"
using namespace std;
struct logData{
double fps;
uint64_t frametime;
@ -70,13 +69,13 @@ private:
extern std::unique_ptr<Logger> logger;
extern string os, cpu, gpu, ram, kernel, driver, cpusched;
extern std::string os, cpu, gpu, ram, kernel, driver, cpusched;
extern bool sysInfoFetched;
extern double fps;
extern uint64_t frametime;
extern logData currentLogData;
string exec(string command);
std::string exec(std::string command);
void autostart_log(int sleep);
#endif //MANGOHUD_LOGGING_H

@ -31,6 +31,7 @@
#endif
namespace fs = ghc::filesystem;
using namespace std;
#ifdef HAVE_DBUS
float g_overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */;

@ -2,7 +2,6 @@
#ifndef MANGOHUD_OVERLAY_H
#define MANGOHUD_OVERLAY_H
#ifndef MANGOAPP_LAYER
#include <string>
#include <stdint.h>
#include <vector>
@ -11,18 +10,13 @@
#include "version.h"
#include "overlay_params.h"
#include "hud_elements.h"
#include "engine_types.h"
#ifdef HAVE_DBUS
#include "dbus_info.h"
extern float g_overflow;
#endif
#endif
#include "logging.h"
#include "notify.h"
#include "vk_enum_to_str.h"
#include <vulkan/vk_layer.h>
using namespace std;
struct frame_stat {
uint64_t stats[OVERLAY_PLOTS_MAX];
@ -30,27 +24,6 @@ struct frame_stat {
static const int kMaxGraphEntries = 50;
enum EngineTypes
{
UNKNOWN,
OPENGL,
VULKAN,
DXVK,
VKD3D,
DAMAVAND,
ZINK,
WINED3D,
FERAL3D,
TOGL,
GAMESCOPE
};
extern const char* engines[];
#ifndef MANGOAPP_LAYER
struct swapchain_stats {
uint64_t n_frames;
enum overlay_plots stat_selector;
@ -107,38 +80,7 @@ struct LOAD_DATA {
unsigned med_load;
unsigned high_load;
};
#endif
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
struct vk_instance_dispatch_table vtable;
VkInstance instance;
struct overlay_params params;
uint32_t api_version;
string engineName, engineVersion;
enum EngineTypes engine;
notify_thread notifier;
int control_client;
};
/* Mapped from VkDevice */
struct queue_data;
struct device_data {
struct instance_data *instance;
PFN_vkSetDeviceLoaderData set_device_loader_data;
struct vk_device_dispatch_table vtable;
VkPhysicalDevice physical_device;
VkDevice device;
VkPhysicalDeviceProperties properties;
struct queue_data *graphic_queue;
std::vector<struct queue_data *> queues;
};
#ifndef MANGOAPP_LAYER
extern struct fps_limit fps_limit_stats;
extern uint32_t deviceID;
@ -171,12 +113,11 @@ void center_text(const std::string& text);
ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current);
float get_time_stat(void *_data, int _idx);
void stop_hw_updater();
extern void control_client_check(struct device_data *device_data);
extern void process_control_socket(struct instance_data *instance_data);
extern void control_client_check(int control, int& control_client, const std::string& deviceName);
extern void process_control_socket(int& control_client, overlay_params &params);
#ifdef HAVE_DBUS
void render_mpris_metadata(const overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);
#endif
void update_fan();
#endif //MANGOAPP_LAYER
#endif //MANGOHUD_OVERLAY_H

@ -96,9 +96,15 @@ parse_position(const char *str)
static int
parse_control(const char *str)
{
int ret = os_socket_listen_abstract(str, 1);
std::string path(str);
size_t npos = path.find("%p");
if (npos != std::string::npos)
path.replace(npos, 2, std::to_string(getpid()));
SPDLOG_DEBUG("Socket: {}", path);
int ret = os_socket_listen_abstract(path.c_str(), 1);
if (ret < 0) {
SPDLOG_ERROR("Couldn't create socket pipe at '{}'\n", str);
SPDLOG_ERROR("Couldn't create socket pipe at '{}'", path);
SPDLOG_ERROR("ERROR: '{}'", strerror(errno));
return ret;
}

@ -50,6 +50,8 @@
#include "blacklist.h"
#include "pci_ids.h"
using namespace std;
float offset_x, offset_y, hudSpacing;
int hudFirstRow, hudSecondRow;
VkPhysicalDeviceDriverProperties driverProps = {};
@ -60,8 +62,37 @@ namespace MangoHud { namespace GL {
}}
#endif
/* Mapped from VkCommandBuffer */
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
struct vk_instance_dispatch_table vtable;
VkInstance instance;
struct overlay_params params;
uint32_t api_version;
string engineName, engineVersion;
enum EngineTypes engine;
notify_thread notifier;
int control_client;
};
/* Mapped from VkDevice */
struct queue_data;
struct device_data {
struct instance_data *instance;
PFN_vkSetDeviceLoaderData set_device_loader_data;
struct vk_device_dispatch_table vtable;
VkPhysicalDevice physical_device;
VkDevice device;
VkPhysicalDeviceProperties properties;
struct queue_data *graphic_queue;
std::vector<struct queue_data *> queues;
};
/* Mapped from VkCommandBuffer */
struct command_buffer_data {
struct device_data *device;
@ -422,8 +453,8 @@ static void snapshot_swapchain_frame(struct swapchain_data *data)
check_keybinds(instance_data->params, device_data->properties.vendorID);
#ifdef __linux__
if (instance_data->params.control >= 0) {
control_client_check(device_data);
process_control_socket(instance_data);
control_client_check(instance_data->params.control, instance_data->control_client, gpu.c_str());
process_control_socket(instance_data->control_client, instance_data->params);
}
#endif
}

Loading…
Cancel
Save