graphics-hook.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #pragma once
  2. #ifdef _MSC_VER
  3. /* conversion from data/function pointer */
  4. #pragma warning(disable : 4152)
  5. #endif
  6. #ifdef OBS_LEGACY
  7. #include "../graphics-hook-info.h"
  8. #else
  9. #include <graphics-hook-info.h>
  10. #endif
  11. #include <ipc-util/pipe.h>
  12. #include <psapi.h>
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #else
  16. #if defined(_MSC_VER) && !defined(inline)
  17. #define inline __inline
  18. #endif
  19. #endif
  20. #define NUM_BUFFERS 3
  21. #define HOOK_VERBOSE_LOGGING 0
  22. #if HOOK_VERBOSE_LOGGING
  23. #define hlog_verbose(...) hlog(__VA_ARGS__)
  24. #else
  25. #define hlog_verbose(...) (void)0
  26. #endif
  27. extern void hlog(const char *format, ...);
  28. extern void hlog_hr(const char *text, HRESULT hr);
  29. static inline const char *get_process_name(void);
  30. static inline HMODULE get_system_module(const char *module);
  31. static inline HMODULE load_system_library(const char *module);
  32. extern uint64_t os_gettime_ns(void);
  33. #define flog(format, ...) hlog("%s: " format, __FUNCTION__, ##__VA_ARGS__)
  34. #define flog_hr(text, hr) hlog_hr(__FUNCTION__ ": " text, hr)
  35. static inline bool capture_active(void);
  36. static inline bool capture_ready(void);
  37. static inline bool capture_should_stop(void);
  38. static inline bool capture_should_init(void);
  39. extern void shmem_copy_data(size_t idx, void *volatile data);
  40. extern bool shmem_texture_data_lock(int idx);
  41. extern void shmem_texture_data_unlock(int idx);
  42. extern bool hook_ddraw(void);
  43. extern bool hook_d3d8(void);
  44. extern bool hook_d3d9(void);
  45. extern bool hook_d3d12(void);
  46. extern bool hook_dxgi(void);
  47. extern bool hook_gl(void);
  48. #ifdef COMPILE_VULKAN_HOOK
  49. extern bool hook_vulkan(void);
  50. #endif
  51. extern void d3d10_capture(void *swap, void *backbuffer);
  52. extern void d3d10_free(void);
  53. extern void d3d11_capture(void *swap, void *backbuffer);
  54. extern void d3d11_free(void);
  55. #ifdef COMPILE_D3D12_HOOK
  56. extern void d3d12_capture(void *swap, void *backbuffer);
  57. extern void d3d12_free(void);
  58. #endif
  59. extern bool rehook_gl(void);
  60. extern bool capture_init_shtex(struct shtex_data **data, HWND window, uint32_t cx, uint32_t cy, uint32_t format,
  61. bool flip, uintptr_t handle);
  62. extern bool capture_init_shmem(struct shmem_data **data, HWND window, uint32_t cx, uint32_t cy, uint32_t pitch,
  63. uint32_t format, bool flip);
  64. extern void capture_free(void);
  65. extern struct hook_info *global_hook_info;
  66. struct vertex {
  67. struct {
  68. float x, y, z, w;
  69. } pos;
  70. struct {
  71. float u, v;
  72. } tex;
  73. };
  74. static inline bool duplicate_handle(HANDLE *dst, HANDLE src)
  75. {
  76. return !!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), dst, 0, false, DUPLICATE_SAME_ACCESS);
  77. }
  78. static inline void *get_offset_addr(HMODULE module, uint32_t offset)
  79. {
  80. return (void *)((uintptr_t)module + (uintptr_t)offset);
  81. }
  82. /* ------------------------------------------------------------------------- */
  83. extern ipc_pipe_client_t pipe;
  84. extern HANDLE signal_restart;
  85. extern HANDLE signal_stop;
  86. extern HANDLE signal_ready;
  87. extern HANDLE signal_exit;
  88. extern HANDLE tex_mutexes[2];
  89. extern char system_path[MAX_PATH];
  90. extern char process_name[MAX_PATH];
  91. extern wchar_t keepalive_name[64];
  92. extern HWND dummy_window;
  93. extern volatile bool active;
  94. static inline const char *get_process_name(void)
  95. {
  96. return process_name;
  97. }
  98. static inline HMODULE get_system_module(const char *module)
  99. {
  100. char base_path[MAX_PATH];
  101. strcpy(base_path, system_path);
  102. strcat(base_path, "\\");
  103. strcat(base_path, module);
  104. return GetModuleHandleA(base_path);
  105. }
  106. static inline uint32_t module_size(HMODULE module)
  107. {
  108. MODULEINFO info;
  109. bool success = !!GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(info));
  110. return success ? info.SizeOfImage : 0;
  111. }
  112. static inline HMODULE load_system_library(const char *name)
  113. {
  114. char base_path[MAX_PATH];
  115. HMODULE module;
  116. strcpy(base_path, system_path);
  117. strcat(base_path, "\\");
  118. strcat(base_path, name);
  119. module = GetModuleHandleA(base_path);
  120. if (module)
  121. return module;
  122. return LoadLibraryA(base_path);
  123. }
  124. static inline bool capture_alive(void)
  125. {
  126. HANDLE handle = OpenMutexW(SYNCHRONIZE, false, keepalive_name);
  127. const bool success = handle != NULL;
  128. if (success)
  129. CloseHandle(handle);
  130. return success;
  131. }
  132. static inline bool capture_active(void)
  133. {
  134. return active;
  135. }
  136. static inline bool frame_ready(uint64_t interval)
  137. {
  138. static uint64_t last_time = 0;
  139. uint64_t elapsed;
  140. uint64_t t;
  141. if (!interval) {
  142. return true;
  143. }
  144. t = os_gettime_ns();
  145. elapsed = t - last_time;
  146. if (elapsed < interval) {
  147. return false;
  148. }
  149. last_time = (elapsed > interval * 2) ? t : last_time + interval;
  150. return true;
  151. }
  152. static inline bool capture_ready(void)
  153. {
  154. return capture_active() && frame_ready(global_hook_info->frame_interval);
  155. }
  156. static inline bool capture_stopped(void)
  157. {
  158. return WaitForSingleObject(signal_stop, 0) == WAIT_OBJECT_0;
  159. }
  160. static inline bool capture_restarted(void)
  161. {
  162. return WaitForSingleObject(signal_restart, 0) == WAIT_OBJECT_0;
  163. }
  164. static inline bool capture_should_stop(void)
  165. {
  166. bool stop_requested = false;
  167. if (capture_active()) {
  168. static uint64_t last_keepalive_check = 0;
  169. uint64_t cur_time = os_gettime_ns();
  170. bool alive = true;
  171. if (cur_time - last_keepalive_check > 5000000000) {
  172. alive = capture_alive();
  173. last_keepalive_check = cur_time;
  174. }
  175. stop_requested = capture_stopped() || !alive;
  176. }
  177. return stop_requested;
  178. }
  179. extern bool init_pipe(void);
  180. static inline bool capture_should_init(void)
  181. {
  182. bool should_init = false;
  183. if (!capture_active()) {
  184. if (capture_restarted()) {
  185. if (capture_alive()) {
  186. if (!ipc_pipe_client_valid(&pipe)) {
  187. init_pipe();
  188. }
  189. should_init = true;
  190. } else {
  191. hlog_verbose("capture_should_init: inactive, restarted, not alive");
  192. }
  193. } else {
  194. hlog_verbose("capture_should_init: inactive, not restarted");
  195. }
  196. }
  197. return should_init;
  198. }
  199. #if COMPILE_VULKAN_HOOK
  200. extern __declspec(thread) int vk_presenting;
  201. #endif
  202. static inline bool should_passthrough()
  203. {
  204. #if COMPILE_VULKAN_HOOK
  205. return vk_presenting > 0;
  206. #else
  207. return false;
  208. #endif
  209. }
  210. #ifdef __cplusplus
  211. }
  212. #endif