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