diff options
| author | aura <nw@moneybot.cc> | 2026-07-13 10:15:03 +0200 |
|---|---|---|
| committer | aura <nw@moneybot.cc> | 2026-07-13 10:15:03 +0200 |
| commit | 57d172df4db1451ba3caeeb0ca485d0845a61912 (patch) | |
| tree | ad0be7c8bec79a1eb58b25f2a631bc4b6809e7fd /src/hooks.cpp | |
push source
Diffstat (limited to 'src/hooks.cpp')
| -rw-r--r-- | src/hooks.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/hooks.cpp b/src/hooks.cpp new file mode 100644 index 0000000..25883b3 --- /dev/null +++ b/src/hooks.cpp @@ -0,0 +1,275 @@ +#include <vulkan/vulkan.h> +#include <vulkan/vk_layer.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <new> + +#include "overlay.h" +#include "vulkan.h" + +#define FH_EXPORT __attribute__(( visibility( "default" ) )) +#define LAYER_NAME "VK_LAYER_fhvkov_overlay" + +VkLayerInstanceCreateInfo* find_instance_link( const VkInstanceCreateInfo* ci ) { + VkLayerInstanceCreateInfo* li = (VkLayerInstanceCreateInfo*)ci->pNext; + while( li && !(li->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && li->function == VK_LAYER_LINK_INFO) ) + li = (VkLayerInstanceCreateInfo*)li->pNext; + return li; +} + +VkLayerDeviceCreateInfo* find_device_link( const VkDeviceCreateInfo* ci ) { + VkLayerDeviceCreateInfo* li = (VkLayerDeviceCreateInfo*)ci->pNext; + while( li && !(li->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && li->function == VK_LAYER_LINK_INFO) ) + li = (VkLayerDeviceCreateInfo*)li->pNext; + return li; +} + +VKAPI_ATTR VkResult VKAPI_CALL hook_create_instance( + const VkInstanceCreateInfo* ci, + const VkAllocationCallbacks* ac, + VkInstance* out +) { + VkLayerInstanceCreateInfo* li = find_instance_link( ci ); + if( !li ) + return VK_ERROR_INITIALIZATION_FAILED; + + PFN_vkGetInstanceProcAddr gipa = li->u.pLayerInfo->pfnNextGetInstanceProcAddr; + li->u.pLayerInfo = li->u.pLayerInfo->pNext; + + PFN_vkCreateInstance create = (PFN_vkCreateInstance)gipa( 0, "vkCreateInstance" ); + if( !create ) + return VK_ERROR_INITIALIZATION_FAILED; + + VkResult r = create( ci, ac, out ); + if( r != VK_SUCCESS ) + return r; + + vk_instance_register(* out, gipa ); + return r; +} + +VKAPI_ATTR void VKAPI_CALL hook_destroy_instance( VkInstance inst, const VkAllocationCallbacks* ac ) { + INSTANCE_DATA* id = vk_find_instance( GET_KEY( inst ) ); + PFN_vkDestroyInstance down = id ? id->destroy_instance : 0; + vk_instance_forget( inst ); + if( down ) + down( inst, ac ); +} + +VKAPI_ATTR VkResult VKAPI_CALL hook_create_device( + VkPhysicalDevice phys, + const VkDeviceCreateInfo* ci, + const VkAllocationCallbacks* ac, + VkDevice* out +) { + VkLayerDeviceCreateInfo* li = find_device_link( ci ); + if( !li ) + return VK_ERROR_INITIALIZATION_FAILED; + + PFN_vkGetInstanceProcAddr gipa = li->u.pLayerInfo->pfnNextGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr gdpa = li->u.pLayerInfo->pfnNextGetDeviceProcAddr; + li->u.pLayerInfo = li->u.pLayerInfo->pNext; + + PFN_vkCreateDevice create = (PFN_vkCreateDevice)gipa( 0, "vkCreateDevice" ); + if( !create ) + return VK_ERROR_INITIALIZATION_FAILED; + + VkResult r = create( phys, ci, ac, out ); + if( r != VK_SUCCESS ) + return r; + + DEVICE_DATA* d = (DEVICE_DATA*)calloc( 1, sizeof(DEVICE_DATA) ); + OVERLAY_DATA* od = overlay_inst(); + d->overlay = od; + new( &d->udp ) UDP_LISTENER(); + new( &d->gauge ) GAUGE_RENDERER(); + + d->key = GET_KEY(* out ); + d->dev =* out; + d->phys = phys; + d->gdpa = gdpa; + d->inst = vk_find_instance( GET_KEY( phys ) ); + + od->t_prev = t_nows(); + vk_resolve_device_procs( d,* out, gdpa ); + + config_init( &od->cfg ); + const char* e = getenv( "FHVKOV_PORT" ); + if( e ) + od->cfg.port = atoi( e ); + + if( !OK( udp_open( &d->udp, od->cfg.port ) ) ) + dlog( "fhvkov: cannot bind udp/%d (%s), overlay will stay hidden\n", od->cfg.port, strerror(errno) ); + else + printf( "fhvkov: active, udp/%d, config %s\n", od->cfg.port, od->cfg.path ); + + vk_device_register( d ); + return r; +} + +VKAPI_ATTR void VKAPI_CALL hook_destroy_device( + VkDevice dev, + const VkAllocationCallbacks* ac +) { + DEVICE_DATA* d = vk_find_device( GET_KEY( dev ) ); + if( !d ) + return; + + for( I32 i = 0; i < MAX_SWAPS; i++ ) { + if( d->swaps[i] ) { + vk_swap_destroy( d, d->swaps[i] ); + d->swaps[i] = 0; + } + } + vk_device_unregister( d ); + + PFN_vkDestroyDevice down = d->destroy_device; + d->udp.~UDP_LISTENER(); + free( d ); + down( dev, ac ); +} + +VKAPI_ATTR void VKAPI_CALL hook_get_device_queue( + VkDevice dev, + U32 family, + U32 index, + VkQueue* q +) { + DEVICE_DATA* d = vk_find_device( GET_KEY( dev ) ); + d->get_device_queue( dev, family, index, q ); + vk_device_add_queue( d,* q, family ); +} + +VKAPI_ATTR void VKAPI_CALL hook_get_device_queue2( + VkDevice dev, + const VkDeviceQueueInfo2* qi, + VkQueue* q +) { + DEVICE_DATA* d = vk_find_device( GET_KEY( dev ) ); + d->get_device_queue2( dev, qi, q ); + vk_device_add_queue( d,* q, qi->queueFamilyIndex ); +} + +VKAPI_ATTR VkResult VKAPI_CALL hook_create_swapchain( + VkDevice dev, + const VkSwapchainCreateInfoKHR* ci, + const VkAllocationCallbacks* ac, + VkSwapchainKHR* out +) { + DEVICE_DATA* d = vk_find_device( GET_KEY( dev ) ); + if( !d ) + return VK_ERROR_INITIALIZATION_FAILED; + + VkSwapchainCreateInfoKHR ci2 =* ci; + ci2.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + VkResult r = d->create_swapchain( dev, &ci2, ac, out ); + if( r != VK_SUCCESS ) + return r; + + vk_swap_create( d,* out, ci ); + return r; +} + +VKAPI_ATTR void VKAPI_CALL hook_destroy_swapchain( + VkDevice dev, + VkSwapchainKHR sc, + const VkAllocationCallbacks* ac +) { + DEVICE_DATA* d = vk_find_device( GET_KEY( dev ) ); + if( !d ) + return; + + vk_swap_forget( d, sc ); + d->destroy_swapchain( dev, sc, ac ); +} + +VKAPI_ATTR VkResult VKAPI_CALL hook_queue_present( + VkQueue queue, + const VkPresentInfoKHR* pi +) { + DEVICE_DATA* d = vk_find_device( GET_KEY( queue ) ); + if( !d ) + return VK_ERROR_DEVICE_LOST; + OVERLAY_DATA* od = d->overlay; + + udp_parse( &d->udp, &od->telem ); + if( ++od->frame % 60 == 0 ) { + if( config_poll( &od->cfg ) ) + od->valid_redline = 0.86; + } + + F64 now = t_nows(); + F64 dt = now - od->t_prev; + od->t_prev = now; + if( dt < 0.0 ) dt = 0.0; + if( dt > 0.1 ) dt = 0.1; + overlay_update( od, now, dt ); + + if( !overlay_visible( od, now ) || pi->swapchainCount != 1 ) + return d->queue_present( queue, pi ); + + pthread_mutex_lock( &g_lock ); + SWAP_DATA* s = vk_find_swap( d, pi->pSwapchains[0] ); + bool ok = s && !s->broken; + if( ok && !s->frames_ready && !OK( vk_swap_setup_frames( d, s, queue ) ) ) { + s->broken = true; + ok = false; + } + pthread_mutex_unlock( &g_lock ); + + if( !ok ) + return d->queue_present( queue, pi ); + return vk_present( d, s, queue, pi ); +} + +#define HOOK( vk_name, fn_name ) \ + if( !strcmp( name, #vk_name ) ) \ + return (PFN_vkVoidFunction)fn_name + +PFN_vkVoidFunction hooked( const char* name ) { + HOOK( vkCreateInstance, hook_create_instance ); + HOOK( vkDestroyInstance, hook_destroy_instance ); + HOOK( vkCreateDevice, hook_create_device ); + HOOK( vkDestroyDevice, hook_destroy_device ); + HOOK( vkGetDeviceQueue, hook_get_device_queue ); + HOOK( vkGetDeviceQueue2, hook_get_device_queue2 ); + HOOK( vkCreateSwapchainKHR, hook_create_swapchain ); + HOOK( vkDestroySwapchainKHR, hook_destroy_swapchain ); + HOOK( vkQueuePresentKHR, hook_queue_present ); + HOOK( vkGetInstanceProcAddr, vkGetInstanceProcAddr ); + HOOK( vkGetDeviceProcAddr, vkGetDeviceProcAddr ); + return 0; +} + +extern "C" { + FH_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vkGetDeviceProcAddr( VkDevice dev, const char* name ); + + FH_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vkGetInstanceProcAddr( VkInstance inst, const char* name ); + + + FH_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vkGetDeviceProcAddr( VkDevice dev, const char* name ) { + PFN_vkVoidFunction f = hooked( name ); + if( f ) + return f; + + DEVICE_DATA* d = dev ? vk_find_device( GET_KEY( dev ) ) : 0; + return d ? d->gdpa( dev, name ) : 0; + } + + FH_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vkGetInstanceProcAddr( VkInstance inst, const char* name ) { + PFN_vkVoidFunction f = hooked( name ); + if( f ) + return f; + + INSTANCE_DATA* id = inst ? vk_find_instance( GET_KEY( inst ) ) : 0; + return id ? id->gipa( inst, name ) : 0; + } +} + |
