mangoapp: vulkan layer

pull/710/head
FlightlessMango 2 years ago
parent 5b1bda770a
commit b064f47d66

File diff suppressed because it is too large Load Diff

@ -17,3 +17,4 @@ option('with_libdrm_amdgpu', type : 'feature', value : 'enabled', description: '
option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build')
option('mangoapp', type: 'boolean', value : 'false')
option('mangohudctl', type: 'boolean', value : 'false')
option('mangoapp_layer', type: 'boolean', value : 'false')

@ -0,0 +1,398 @@
#include <mutex>
#include <list>
#include <unordered_map>
#include <sys/stat.h>
#include <unistd.h>
#include "overlay.h"
#include <inttypes.h>
#include "mesa/util/macros.h"
#include <vulkan/vk_util.h>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
VkPhysicalDeviceDriverProperties driverProps = {};
/* Mapped from VkCommandBuffer */
struct queue_data;
/* Mapped from VkQueue */
struct queue_data {
struct device_data *device;
VkQueue queue;
VkQueueFlags flags;
uint32_t family_index;
};
// single global lock, for simplicity
std::mutex global_lock;
typedef std::lock_guard<std::mutex> scoped_lock;
std::unordered_map<uint64_t, void *> vk_object_to_data;
#define HKEY(obj) ((uint64_t)(obj))
#define FIND(type, obj) (reinterpret_cast<type *>(find_object_data(HKEY(obj))))
static void *find_object_data(uint64_t obj)
{
::scoped_lock lk(global_lock);
return vk_object_to_data[obj];
}
static void map_object(uint64_t obj, void *data)
{
::scoped_lock lk(global_lock);
vk_object_to_data[obj] = data;
}
static void unmap_object(uint64_t obj)
{
::scoped_lock lk(global_lock);
vk_object_to_data.erase(obj);
}
static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
VkLayerFunction func)
{
vk_foreach_struct(item, pCreateInfo->pNext) {
if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
((VkLayerInstanceCreateInfo *) item)->function == func)
return (VkLayerInstanceCreateInfo *) item;
}
unreachable("instance chain info not found");
return NULL;
}
static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,
VkLayerFunction func)
{
vk_foreach_struct(item, pCreateInfo->pNext) {
if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
((VkLayerDeviceCreateInfo *) item)->function == func)
return (VkLayerDeviceCreateInfo *)item;
}
unreachable("device chain info not found");
return NULL;
}
/**/
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;
}
static void destroy_instance_data(struct instance_data *data)
{
unmap_object(HKEY(data->instance));
delete data;
}
static void instance_data_map_physical_devices(struct instance_data *instance_data,
bool map)
{
uint32_t physicalDeviceCount = 0;
instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,
&physicalDeviceCount,
NULL);
std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,
&physicalDeviceCount,
physicalDevices.data());
for (uint32_t i = 0; i < physicalDeviceCount; i++) {
if (map)
map_object(HKEY(physicalDevices[i]), instance_data);
else
unmap_object(HKEY(physicalDevices[i]));
}
}
/**/
static struct device_data *new_device_data(VkDevice device, struct instance_data *instance)
{
struct device_data *data = new device_data();
data->instance = instance;
data->device = device;
map_object(HKEY(data->device), data);
return data;
}
static void destroy_queue(struct queue_data *data)
{
unmap_object(HKEY(data->queue));
delete data;
}
static void device_unmap_queues(struct device_data *data)
{
for (auto q : data->queues)
destroy_queue(q);
}
static void destroy_device_data(struct device_data *data)
{
unmap_object(HKEY(data->device));
delete data;
}
static VkResult overlay_CreateDevice(
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice)
{
struct instance_data *instance_data =
FIND(struct instance_data, physicalDevice);
VkLayerDeviceCreateInfo *chain_info =
get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
assert(chain_info->u.pLayerInfo);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
if (fpCreateDevice == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Advance the link info for the next element on the chain
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkPhysicalDeviceFeatures device_features = {};
VkDeviceCreateInfo device_info = *pCreateInfo;
std::vector<const char*> enabled_extensions(device_info.ppEnabledExtensionNames,
device_info.ppEnabledExtensionNames +
device_info.enabledExtensionCount);
uint32_t extension_count;
instance_data->vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, nullptr);
std::vector<VkExtensionProperties> available_extensions(extension_count);
instance_data->vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, available_extensions.data());
bool can_get_driver_info = instance_data->api_version < VK_API_VERSION_1_1 ? false : true;
// VK_KHR_driver_properties became core in 1.2
if (instance_data->api_version < VK_API_VERSION_1_2 && can_get_driver_info) {
for (auto& extension : available_extensions) {
if (extension.extensionName == std::string(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) {
for (auto& enabled : enabled_extensions) {
if (enabled == std::string(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME))
goto DONT;
}
enabled_extensions.push_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME);
DONT:
goto FOUND;
}
}
can_get_driver_info = false;
FOUND:;
}
device_info.enabledExtensionCount = enabled_extensions.size();
device_info.ppEnabledExtensionNames = enabled_extensions.data();
if (pCreateInfo->pEnabledFeatures)
device_features = *(pCreateInfo->pEnabledFeatures);
device_info.pEnabledFeatures = &device_features;
VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice);
if (result != VK_SUCCESS) return result;
struct device_data *device_data = new_device_data(*pDevice, instance_data);
device_data->physical_device = physicalDevice;
vk_load_device_commands(*pDevice, fpGetDeviceProcAddr, &device_data->vtable);
instance_data->vtable.GetPhysicalDeviceProperties(device_data->physical_device,
&device_data->properties);
VkLayerDeviceCreateInfo *load_data_info =
get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;
driverProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
driverProps.pNext = nullptr;
if (can_get_driver_info) {
VkPhysicalDeviceProperties2 deviceProps = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &driverProps};
instance_data->vtable.GetPhysicalDeviceProperties2(device_data->physical_device, &deviceProps);
}
return result;
}
static void overlay_DestroyDevice(
VkDevice device,
const VkAllocationCallbacks* pAllocator)
{
struct device_data *device_data = FIND(struct device_data, device);
device_unmap_queues(device_data);
device_data->vtable.DestroyDevice(device, pAllocator);
destroy_device_data(device_data);
}
static VkResult overlay_CreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance)
{
VkLayerInstanceCreateInfo *chain_info =
get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
std::string engineVersion,engineName;
enum EngineTypes engine = EngineTypes::UNKNOWN;
const char* pEngineName = nullptr;
if (pCreateInfo->pApplicationInfo)
pEngineName = pCreateInfo->pApplicationInfo->pEngineName;
if (pEngineName)
engineName = pEngineName;
if (engineName == "DXVK" || engineName == "vkd3d") {
int engineVer = pCreateInfo->pApplicationInfo->engineVersion;
engineVersion = to_string(VK_VERSION_MAJOR(engineVer)) + "." + to_string(VK_VERSION_MINOR(engineVer)) + "." + to_string(VK_VERSION_PATCH(engineVer));
}
if (engineName == "DXVK")
engine = DXVK;
else if (engineName == "vkd3d")
engine = VKD3D;
else if(engineName == "mesa zink")
engine = ZINK;
else if (engineName == "Damavand")
engine = DAMAVAND;
else if (engineName == "Feral3D")
engine = FERAL3D;
else
engine = VULKAN;
assert(chain_info->u.pLayerInfo);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkCreateInstance fpCreateInstance =
(PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
if (fpCreateInstance == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Advance the link info for the next element on the chain
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
if (result != VK_SUCCESS) return result;
struct instance_data *instance_data = new_instance_data(*pInstance);
vk_load_instance_commands(instance_data->instance,
fpGetInstanceProcAddr,
&instance_data->vtable);
instance_data_map_physical_devices(instance_data, true);
instance_data->engine = engine;
instance_data->engineName = engineName;
instance_data->engineVersion = engineVersion;
struct stat info;
// string path = "/var/run/user/" + to_string(getuid()) + "/mangoapp/";
string path = "/tmp/mangoapp/";
string command = "mkdir -p " + path;
string json_path = path + to_string(getpid()) + ".json";
if( stat(path.c_str(), &info ) != 0 )
system(command.c_str());
json j;
j["engine"] = engine;
ofstream o(json_path);
if (!o.fail()){
o << std::setw(4) << j << std::endl;
} else{
fprintf(stderr, "MANGOAPP LAYER: failed to write json\n");
}
o.close();
return result;
}
static void overlay_DestroyInstance(
VkInstance instance,
const VkAllocationCallbacks* pAllocator)
{
struct instance_data *instance_data = FIND(struct instance_data, instance);
instance_data_map_physical_devices(instance_data, false);
instance_data->vtable.DestroyInstance(instance, pAllocator);
destroy_instance_data(instance_data);
}
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev,
const char *funcName);
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance,
const char *funcName);
static const struct {
const char *name;
void *ptr;
} name_to_funcptr_map[] = {
{ "vkGetInstanceProcAddr", (void *) overlay_GetInstanceProcAddr },
{ "vkGetDeviceProcAddr", (void *) overlay_GetDeviceProcAddr },
#define ADD_HOOK(fn) { "vk" # fn, (void *) overlay_ ## fn }
#define ADD_ALIAS_HOOK(alias, fn) { "vk" # alias, (void *) overlay_ ## fn }
ADD_HOOK(CreateDevice),
ADD_HOOK(DestroyDevice),
ADD_HOOK(CreateInstance),
ADD_HOOK(DestroyInstance),
#undef ADD_HOOK
};
static void *find_ptr(const char *name)
{
std::string f(name);
if ((f != "vkCreateInstance" && f != "vkDestroyInstance" && f != "vkCreateDevice" && f != "vkDestroyDevice"))
{
return NULL;
}
for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {
if (strcmp(name, name_to_funcptr_map[i].name) == 0)
return name_to_funcptr_map[i].ptr;
}
return NULL;
}
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev,
const char *funcName)
{
void *ptr = find_ptr(funcName);
if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);
if (dev == NULL) return NULL;
struct device_data *device_data = FIND(struct device_data, dev);
if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;
return device_data->vtable.GetDeviceProcAddr(dev, funcName);
}
extern "C" VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance,
const char *funcName)
{
void *ptr = find_ptr(funcName);
if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);
if (instance == NULL) return NULL;
struct instance_data *instance_data = FIND(struct instance_data, instance);
if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;
return instance_data->vtable.GetInstanceProcAddr(instance, funcName);
}

@ -0,0 +1,21 @@
{
"file_format_version" : "1.0.0",
"layer" : {
"name": "VK_LAYER_MANGOAPP_overlay",
"type": "GLOBAL",
"api_version": "1.2.135",
"library_path": "libMangoApp.so",
"implementation_version": "1",
"description": "Mangoapp Layer",
"functions": {
"vkGetInstanceProcAddr": "overlay_GetInstanceProcAddr",
"vkGetDeviceProcAddr": "overlay_GetDeviceProcAddr"
},
"enable_environment": {
"MANGOAPP": "1"
},
"disable_environment": {
"DISABLE_MANGOAPP": "1"
}
}
}

@ -18,6 +18,9 @@
#include <GLFW/glfw3native.h>
#include <X11/Xatom.h>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
@ -124,6 +127,7 @@ void msg_read_thread(){
}
int key = ftok("mangoapp", 65);
msgid = msgget(key, 0666 | IPC_CREAT);
pid_t previous_pid;
const struct mangoapp_msg_header *hdr = (const struct mangoapp_msg_header*) raw_msg;
const struct mangoapp_msg_v1 *mangoapp_v1 = (const struct mangoapp_msg_v1*) raw_msg;
while (1){
@ -138,6 +142,19 @@ void msg_read_thread(){
if (params->fsr_steam_sharpness < 0)
g_fsrSharpness = mangoapp_v1->fsrSharpness;
}
if (mangoapp_v1->pid != previous_pid){
fprintf(stderr, "PID: %i\n", mangoapp_v1->pid);
string path = "/tmp/mangoapp/" + to_string(mangoapp_v1->pid) + ".json";
ifstream i(path);
if (i.fail()){
sw_stats.engine = EngineTypes::GAMESCOPE;
} else {
json j;
i >> j;
sw_stats.engine = static_cast<EngineTypes> (j["engine"]);
}
previous_pid = mangoapp_v1->pid;
}
if (msg_size > offsetof(mangoapp_msg_v1, latency_ns)){
gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns);
}

@ -273,6 +273,28 @@ mangoapp = executable(
)
endif
if get_option('mangoapp_layer')
pre_args += '-DMANGOAPP_LAYER'
mangoapp_layer = shared_library(
'MangoApp',
vk_enum_to_str,
files(
'app/layer.cpp',
),
c_args : [
pre_args,
no_override_init_args,
],
cpp_args : [
pre_args,
],
gnu_symbol_visibility : 'hidden',
include_directories : [inc_common],
link_args : link_args,
install : true
)
endif
configure_file(input : 'mangohud.json.in',
output : '@0@.json'.format(meson.project_name()),
configuration : {'ld_libdir_mangohud' : ld_libdir_mangohud_vk,
@ -294,3 +316,10 @@ if get_option('include_doc')
rename : ['MangoHud.conf.example']
)
endif
configure_file(input : 'app/layer.json.in',
output : 'libMangoApp.json',
copy: true,
install : true,
install_dir : join_paths(get_option('datadir'), 'vulkan', 'implicit_layer.d'),
)

@ -2,6 +2,7 @@
#ifndef MANGOHUD_OVERLAY_H
#define MANGOHUD_OVERLAY_H
#ifndef MANGOAPP_LAYER
#include <string>
#include <stdint.h>
#include <vector>
@ -13,16 +14,20 @@
#include "hud_elements.h"
#include "version.h"
#include "gpu.h"
#include "logging.h"
#include "vk_enum_to_str.h"
#include "notify.h"
#include <vulkan/vk_layer.h>
#include "amdgpu.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];
};
@ -49,7 +54,7 @@ enum EngineTypes
};
extern const char* engines[];
#ifndef MANGOAPP_LAYER
struct swapchain_stats {
uint64_t n_frames;
enum overlay_plots stat_selector;
@ -106,7 +111,7 @@ struct LOAD_DATA {
unsigned med_load;
unsigned high_load;
};
#endif
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
struct vk_instance_dispatch_table vtable;
@ -137,6 +142,7 @@ struct device_data {
std::vector<struct queue_data *> queues;
};
#ifndef MANGOAPP_LAYER
extern struct fps_limit fps_limit_stats;
extern int32_t deviceID;
@ -168,9 +174,9 @@ 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);
#ifdef HAVE_DBUS
void render_mpris_metadata(overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);
#endif
#endif
#endif //MANGOHUD_OVERLAY_H

Loading…
Cancel
Save