#pragma once #ifdef _MSC_VER /* conversion from data/function pointer */ #pragma warning(disable : 4152) #endif #ifdef OBS_LEGACY #include "../graphics-hook-info.h" #else #include #endif #include #include #ifdef __cplusplus extern "C" { #else #if defined(_MSC_VER) && !defined(inline) #define inline __inline #endif #endif #define NUM_BUFFERS 3 #define HOOK_VERBOSE_LOGGING 0 #if HOOK_VERBOSE_LOGGING #define hlog_verbose(...) hlog(__VA_ARGS__) #else #define hlog_verbose(...) (void)0 #endif extern void hlog(const char *format, ...); extern void hlog_hr(const char *text, HRESULT hr); static inline const char *get_process_name(void); static inline HMODULE get_system_module(const char *module); static inline HMODULE load_system_library(const char *module); extern uint64_t os_gettime_ns(void); #define flog(format, ...) hlog("%s: " format, __FUNCTION__, ##__VA_ARGS__) #define flog_hr(text, hr) hlog_hr(__FUNCTION__ ": " text, hr) static inline bool capture_active(void); static inline bool capture_ready(void); static inline bool capture_should_stop(void); static inline bool capture_should_init(void); extern void shmem_copy_data(size_t idx, void *volatile data); extern bool shmem_texture_data_lock(int idx); extern void shmem_texture_data_unlock(int idx); extern bool hook_ddraw(void); extern bool hook_d3d8(void); extern bool hook_d3d9(void); extern bool hook_d3d12(void); extern bool hook_dxgi(void); extern bool hook_gl(void); #ifdef COMPILE_VULKAN_HOOK extern bool hook_vulkan(void); #endif extern void d3d10_capture(void *swap, void *backbuffer); extern void d3d10_free(void); extern void d3d11_capture(void *swap, void *backbuffer); extern void d3d11_free(void); #ifdef COMPILE_D3D12_HOOK extern void d3d12_capture(void *swap, void *backbuffer); extern void d3d12_free(void); #endif extern bool rehook_gl(void); extern bool capture_init_shtex(struct shtex_data **data, HWND window, uint32_t cx, uint32_t cy, uint32_t format, bool flip, uintptr_t handle); extern bool capture_init_shmem(struct shmem_data **data, HWND window, uint32_t cx, uint32_t cy, uint32_t pitch, uint32_t format, bool flip); extern void capture_free(void); extern struct hook_info *global_hook_info; struct vertex { struct { float x, y, z, w; } pos; struct { float u, v; } tex; }; static inline bool duplicate_handle(HANDLE *dst, HANDLE src) { return !!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), dst, 0, false, DUPLICATE_SAME_ACCESS); } static inline void *get_offset_addr(HMODULE module, uint32_t offset) { return (void *)((uintptr_t)module + (uintptr_t)offset); } /* ------------------------------------------------------------------------- */ extern ipc_pipe_client_t pipe; extern HANDLE signal_restart; extern HANDLE signal_stop; extern HANDLE signal_ready; extern HANDLE signal_exit; extern HANDLE tex_mutexes[2]; extern char system_path[MAX_PATH]; extern char process_name[MAX_PATH]; extern wchar_t keepalive_name[64]; extern HWND dummy_window; extern volatile bool active; static inline const char *get_process_name(void) { return process_name; } static inline HMODULE get_system_module(const char *module) { char base_path[MAX_PATH]; strcpy(base_path, system_path); strcat(base_path, "\\"); strcat(base_path, module); return GetModuleHandleA(base_path); } static inline uint32_t module_size(HMODULE module) { MODULEINFO info; bool success = !!GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(info)); return success ? info.SizeOfImage : 0; } static inline HMODULE load_system_library(const char *name) { char base_path[MAX_PATH]; HMODULE module; strcpy(base_path, system_path); strcat(base_path, "\\"); strcat(base_path, name); module = GetModuleHandleA(base_path); if (module) return module; return LoadLibraryA(base_path); } static inline bool capture_alive(void) { HANDLE handle = OpenMutexW(SYNCHRONIZE, false, keepalive_name); const bool success = handle != NULL; if (success) CloseHandle(handle); return success; } static inline bool capture_active(void) { return active; } static inline bool frame_ready(uint64_t interval) { static uint64_t last_time = 0; uint64_t elapsed; uint64_t t; if (!interval) { return true; } t = os_gettime_ns(); elapsed = t - last_time; if (elapsed < interval) { return false; } last_time = (elapsed > interval * 2) ? t : last_time + interval; return true; } static inline bool capture_ready(void) { return capture_active() && frame_ready(global_hook_info->frame_interval); } static inline bool capture_stopped(void) { return WaitForSingleObject(signal_stop, 0) == WAIT_OBJECT_0; } static inline bool capture_restarted(void) { return WaitForSingleObject(signal_restart, 0) == WAIT_OBJECT_0; } static inline bool capture_should_stop(void) { bool stop_requested = false; if (capture_active()) { static uint64_t last_keepalive_check = 0; uint64_t cur_time = os_gettime_ns(); bool alive = true; if (cur_time - last_keepalive_check > 5000000000) { alive = capture_alive(); last_keepalive_check = cur_time; } stop_requested = capture_stopped() || !alive; } return stop_requested; } extern bool init_pipe(void); static inline bool capture_should_init(void) { bool should_init = false; if (!capture_active()) { if (capture_restarted()) { if (capture_alive()) { if (!ipc_pipe_client_valid(&pipe)) { init_pipe(); } should_init = true; } else { hlog_verbose( "capture_should_init: inactive, restarted, not alive"); } } else { hlog_verbose( "capture_should_init: inactive, not restarted"); } } return should_init; } #if COMPILE_VULKAN_HOOK extern __declspec(thread) int vk_presenting; #endif static inline bool should_passthrough() { #if COMPILE_VULKAN_HOOK return vk_presenting > 0; #else return false; #endif } #ifdef __cplusplus } #endif