mirror of
https://github.com/flightlessmango/MangoHud.git
synced 2024-11-11 19:10:55 +00:00
mangohud control
This commit is contained in:
parent
5fee3bc5e3
commit
45be485a13
197
src/control.cpp
Normal file
197
src/control.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
#include <assert.h>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include "mesa/util/os_socket.h"
|
||||
#include "overlay.h"
|
||||
|
||||
using namespace std;
|
||||
static void parse_command(struct instance_data *instance_data,
|
||||
const char *cmd, unsigned cmdlen,
|
||||
const char *param, unsigned paramlen)
|
||||
{
|
||||
if (!strncmp(cmd, "hud", cmdlen)) {
|
||||
_params->no_display = !_params->no_display;
|
||||
}
|
||||
}
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
/**
|
||||
* This function will process commands through the control file.
|
||||
*
|
||||
* A command starts with a colon, followed by the command, and followed by an
|
||||
* option '=' and a parameter. It has to end with a semi-colon. A full command
|
||||
* + parameter looks like:
|
||||
*
|
||||
* :cmd=param;
|
||||
*/
|
||||
static void process_char(struct instance_data *instance_data, char c)
|
||||
{
|
||||
static char cmd[BUFSIZE];
|
||||
static char param[BUFSIZE];
|
||||
|
||||
static unsigned cmdpos = 0;
|
||||
static unsigned parampos = 0;
|
||||
static bool reading_cmd = false;
|
||||
static bool reading_param = false;
|
||||
|
||||
switch (c) {
|
||||
case ':':
|
||||
cmdpos = 0;
|
||||
parampos = 0;
|
||||
reading_cmd = true;
|
||||
reading_param = false;
|
||||
break;
|
||||
case ';':
|
||||
if (!reading_cmd)
|
||||
break;
|
||||
cmd[cmdpos++] = '\0';
|
||||
param[parampos++] = '\0';
|
||||
parse_command(instance_data, cmd, cmdpos, param, parampos);
|
||||
reading_cmd = false;
|
||||
reading_param = false;
|
||||
break;
|
||||
case '=':
|
||||
if (!reading_cmd)
|
||||
break;
|
||||
reading_param = true;
|
||||
break;
|
||||
default:
|
||||
if (!reading_cmd)
|
||||
break;
|
||||
|
||||
if (reading_param) {
|
||||
/* overflow means an invalid parameter */
|
||||
if (parampos >= BUFSIZE - 1) {
|
||||
reading_cmd = false;
|
||||
reading_param = false;
|
||||
break;
|
||||
}
|
||||
|
||||
param[parampos++] = c;
|
||||
} else {
|
||||
/* overflow means an invalid command */
|
||||
if (cmdpos >= BUFSIZE - 1) {
|
||||
reading_cmd = false;
|
||||
break;
|
||||
}
|
||||
|
||||
cmd[cmdpos++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void control_send(struct instance_data *instance_data,
|
||||
const char *cmd, unsigned cmdlen,
|
||||
const char *param, unsigned paramlen)
|
||||
{
|
||||
unsigned msglen = 0;
|
||||
char buffer[BUFSIZE];
|
||||
|
||||
assert(cmdlen + paramlen + 3 < BUFSIZE);
|
||||
|
||||
buffer[msglen++] = ':';
|
||||
|
||||
memcpy(&buffer[msglen], cmd, cmdlen);
|
||||
msglen += cmdlen;
|
||||
|
||||
if (paramlen > 0) {
|
||||
buffer[msglen++] = '=';
|
||||
memcpy(&buffer[msglen], param, paramlen);
|
||||
msglen += paramlen;
|
||||
buffer[msglen++] = ';';
|
||||
}
|
||||
|
||||
os_socket_send(instance_data->control_client, buffer, msglen, 0);
|
||||
}
|
||||
|
||||
static void control_send_connection_string(struct device_data *device_data)
|
||||
{
|
||||
struct instance_data *instance_data = device_data->instance;
|
||||
|
||||
const char *controlVersionCmd = "MesaOverlayControlVersion";
|
||||
const char *controlVersionString = "1";
|
||||
|
||||
control_send(instance_data, 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));
|
||||
|
||||
const char *mesaVersionCmd = "MesaVersion";
|
||||
const char *mesaVersionString = "Mesa";
|
||||
|
||||
control_send(instance_data, mesaVersionCmd, strlen(mesaVersionCmd),
|
||||
mesaVersionString, strlen(mesaVersionString));
|
||||
|
||||
}
|
||||
|
||||
void control_client_check(struct device_data *device_data)
|
||||
{
|
||||
struct instance_data *instance_data = device_data->instance;
|
||||
|
||||
/* Already connected, just return. */
|
||||
if (instance_data->control_client >= 0)
|
||||
return;
|
||||
|
||||
int socket = os_socket_accept(instance_data->params.control);
|
||||
if (socket == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED)
|
||||
fprintf(stderr, "ERROR on socket: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (socket >= 0) {
|
||||
os_socket_block(socket, false);
|
||||
instance_data->control_client = socket;
|
||||
control_send_connection_string(device_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void control_client_disconnected(struct instance_data *instance_data)
|
||||
{
|
||||
os_socket_close(instance_data->control_client);
|
||||
instance_data->control_client = -1;
|
||||
}
|
||||
|
||||
void process_control_socket(struct instance_data *instance_data)
|
||||
{
|
||||
const int client = instance_data->control_client;
|
||||
if (client >= 0) {
|
||||
char buf[BUFSIZE];
|
||||
|
||||
while (true) {
|
||||
ssize_t n = os_socket_recv(client, buf, BUFSIZE, 0);
|
||||
|
||||
if (n == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
/* nothing to read, try again later */
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno != ECONNRESET)
|
||||
fprintf(stderr, "ERROR on connection: %s\n", strerror(errno));
|
||||
|
||||
control_client_disconnected(instance_data);
|
||||
} else if (n == 0) {
|
||||
/* recv() returns 0 when the client disconnects */
|
||||
control_client_disconnected(instance_data);
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < n; i++) {
|
||||
process_char(instance_data, buf[i]);
|
||||
}
|
||||
|
||||
/* If we try to read BUFSIZE and receive BUFSIZE bytes from the
|
||||
* socket, there's a good chance that there's still more data to be
|
||||
* read, so we will try again. Otherwise, simply be done for this
|
||||
* iteration and try again on the next frame.
|
||||
*/
|
||||
if (n < BUFSIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -80,6 +80,7 @@ if is_unixy
|
||||
'real_dlsym.cpp',
|
||||
'pci_ids.cpp',
|
||||
'battery.cpp',
|
||||
'control.cpp',
|
||||
)
|
||||
|
||||
opengl_files = files(
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include "version.h"
|
||||
#include "gpu.h"
|
||||
#include "logging.h"
|
||||
#include "vk_enum_to_str.h"
|
||||
#include "notify.h"
|
||||
#include <vulkan/vk_layer.h>
|
||||
#ifdef HAVE_DBUS
|
||||
#include "dbus_info.h"
|
||||
extern float g_overflow;
|
||||
@ -98,6 +101,36 @@ struct LOAD_DATA {
|
||||
unsigned high_load;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
extern struct fps_limit fps_limit_stats;
|
||||
extern int32_t deviceID;
|
||||
|
||||
@ -124,6 +157,8 @@ 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);
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
void render_mpris_metadata(overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);
|
||||
|
@ -66,35 +66,6 @@ namespace MangoHud { namespace GL {
|
||||
}}
|
||||
#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;
|
||||
};
|
||||
|
||||
/* 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 queue_data;
|
||||
struct command_buffer_data {
|
||||
@ -456,11 +427,10 @@ static void snapshot_swapchain_frame(struct swapchain_data *data)
|
||||
update_hud_info(data->sw_stats, instance_data->params, device_data->properties.vendorID);
|
||||
check_keybinds(data->sw_stats, instance_data->params, device_data->properties.vendorID);
|
||||
|
||||
// not currently used
|
||||
// if (instance_data->params.control >= 0) {
|
||||
// control_client_check(device_data);
|
||||
// process_control_socket(instance_data);
|
||||
// }
|
||||
if (instance_data->params.control >= 0) {
|
||||
control_client_check(device_data);
|
||||
process_control_socket(instance_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void compute_swapchain_display(struct swapchain_data *data)
|
||||
|
Loading…
Reference in New Issue
Block a user