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