forked from FEX-Emu/FEX
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHost.cpp
268 lines (219 loc) · 12.3 KB
/
Host.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
$info$
tags: thunklibs|Vulkan
$end_info$
*/
#define VK_USE_64_BIT_PTR_DEFINES 0
#define VK_USE_PLATFORM_XLIB_XRANDR_EXT
#define VK_USE_PLATFORM_XLIB_KHR
#define VK_USE_PLATFORM_XCB_KHR
#define VK_USE_PLATFORM_WAYLAND_KHR
#include <vulkan/vulkan.h>
#include "common/Host.h"
#include <cstring>
#include <mutex>
#include <string_view>
#include "thunkgen_host_libvulkan.inl"
#include <common/X11Manager.h>
static bool SetupInstance {};
static std::mutex SetupMutex {};
#define LDR_PTR(fn) fexldr_ptr_libvulkan_##fn
static void DoSetupWithInstance(VkInstance instance) {
std::unique_lock lk {SetupMutex};
// Needed since the Guest-endpoint calls without a function pointer
// TODO: Support use of multiple instances
(void*&)LDR_PTR(vkGetDeviceProcAddr) = (void*)LDR_PTR(vkGetInstanceProcAddr)(instance, "vkGetDeviceProcAddr");
if (LDR_PTR(vkGetDeviceProcAddr) == nullptr) {
std::abort();
}
// Query pointers for non-EXT functions customized below
(void*&)LDR_PTR(vkCreateDevice) = (void*)LDR_PTR(vkGetInstanceProcAddr)(instance, "vkCreateDevice");
// Only do this lookup once.
// NOTE: If vkGetInstanceProcAddr was called with a null instance, only a few function pointers will be filled with non-null values, so we do repeat the lookup in that case
if (instance) {
SetupInstance = true;
}
}
#define FEXFN_IMPL(fn) fexfn_impl_libvulkan_##fn
static X11Manager x11_manager;
static void fexfn_impl_libvulkan_SetGuestXGetVisualInfo(uintptr_t GuestTarget, uintptr_t GuestUnpacker) {
MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &x11_manager.GuestXGetVisualInfo);
}
static void fexfn_impl_libvulkan_SetGuestXSync(uintptr_t GuestTarget, uintptr_t GuestUnpacker) {
MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &x11_manager.GuestXSync);
}
static void fexfn_impl_libvulkan_SetGuestXDisplayString(uintptr_t GuestTarget, uintptr_t GuestUnpacker) {
MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &x11_manager.GuestXDisplayString);
}
void fex_custom_repack_entry(host_layout<VkXcbSurfaceCreateInfoKHR>& to, const guest_layout<VkXcbSurfaceCreateInfoKHR>& from) {
// TODO: xcb_aux_sync?
to.data.connection = x11_manager.GuestToHostConnection(const_cast<xcb_connection_t*>(from.data.connection.force_get_host_pointer()));
}
bool fex_custom_repack_exit(guest_layout<VkXcbSurfaceCreateInfoKHR>&, const host_layout<VkXcbSurfaceCreateInfoKHR>&) {
// TODO: xcb_sync?
return false;
}
void fex_custom_repack_entry(host_layout<VkXlibSurfaceCreateInfoKHR>& to, const guest_layout<VkXlibSurfaceCreateInfoKHR>& from) {
to.data.dpy = x11_manager.GuestToHostDisplay(const_cast<Display*>(from.data.dpy.force_get_host_pointer()));
}
bool fex_custom_repack_exit(guest_layout<VkXlibSurfaceCreateInfoKHR>&, const host_layout<VkXlibSurfaceCreateInfoKHR>& from) {
x11_manager.HostXFlush(from.data.dpy);
return false;
}
static VkResult fexfn_impl_libvulkan_vkAcquireXlibDisplayEXT(VkPhysicalDevice a_0, guest_layout<Display*> a_1, VkDisplayKHR a_2) {
auto host_display = x11_manager.GuestToHostDisplay(a_1.force_get_host_pointer());
auto ret = fexldr_ptr_libvulkan_vkAcquireXlibDisplayEXT(a_0, host_display, a_2);
x11_manager.HostXFlush(host_display);
return ret;
}
static VkResult fexfn_impl_libvulkan_vkGetRandROutputDisplayEXT(VkPhysicalDevice a_0, guest_layout<Display*> a_1, RROutput a_2, VkDisplayKHR* a_3) {
auto host_display = x11_manager.GuestToHostDisplay(a_1.force_get_host_pointer());
auto ret = fexldr_ptr_libvulkan_vkGetRandROutputDisplayEXT(a_0, host_display, a_2, a_3);
x11_manager.HostXFlush(host_display);
return ret;
}
static VkBool32 fexfn_impl_libvulkan_vkGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice a_0, uint32_t a_1,
guest_layout<xcb_connection_t*> a_2, xcb_visualid_t a_3) {
auto host_connection = x11_manager.GuestToHostConnection(a_2.force_get_host_pointer());
return fexldr_ptr_libvulkan_vkGetPhysicalDeviceXcbPresentationSupportKHR(a_0, a_1, host_connection, a_3);
}
static VkBool32 fexfn_impl_libvulkan_vkGetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice a_0, uint32_t a_1,
guest_layout<Display*> a_2, VisualID a_3) {
auto host_display = x11_manager.GuestToHostDisplay(a_2.force_get_host_pointer());
auto ret = fexldr_ptr_libvulkan_vkGetPhysicalDeviceXlibPresentationSupportKHR(a_0, a_1, host_display, a_3);
x11_manager.HostXFlush(host_display);
return ret;
}
// Functions with callbacks are overridden to ignore the guest-side callbacks
static VkResult
FEXFN_IMPL(vkCreateShaderModule)(VkDevice a_0, const VkShaderModuleCreateInfo* a_1, const VkAllocationCallbacks* a_2, VkShaderModule* a_3) {
(void*&)LDR_PTR(vkCreateShaderModule) = (void*)LDR_PTR(vkGetDeviceProcAddr)(a_0, "vkCreateShaderModule");
return LDR_PTR(vkCreateShaderModule)(a_0, a_1, nullptr, a_3);
}
static VkBool32
DummyVkDebugReportCallback(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char*, const char*, void*) {
return VK_FALSE;
}
static VkResult FEXFN_IMPL(vkCreateInstance)(const VkInstanceCreateInfo* a_0, const VkAllocationCallbacks* a_1, guest_layout<VkInstance*> a_2) {
const VkInstanceCreateInfo* vk_struct_base = a_0;
for (const VkBaseInStructure* vk_struct = reinterpret_cast<const VkBaseInStructure*>(vk_struct_base); vk_struct->pNext;
vk_struct = vk_struct->pNext) {
// Override guest callbacks used for VK_EXT_debug_report
if (reinterpret_cast<const VkBaseInStructure*>(vk_struct->pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
// Overwrite the pNext pointer, ignoring its const-qualifier
const_cast<VkBaseInStructure*>(vk_struct)->pNext = vk_struct->pNext->pNext;
// If we copied over a nullptr for pNext then early exit
if (!vk_struct->pNext) {
break;
}
}
}
VkInstance out;
auto ret = LDR_PTR(vkCreateInstance)(vk_struct_base, nullptr, &out);
if (ret == VK_SUCCESS) {
*a_2.get_pointer() = to_guest(to_host_layout(out));
}
return ret;
}
static VkResult FEXFN_IMPL(vkCreateDevice)(VkPhysicalDevice a_0, const VkDeviceCreateInfo* a_1, const VkAllocationCallbacks* a_2,
guest_layout<VkDevice*> a_3) {
VkDevice out;
auto ret = LDR_PTR(vkCreateDevice)(a_0, a_1, nullptr, &out);
if (ret == VK_SUCCESS) {
*a_3.get_pointer() = to_guest(to_host_layout(out));
}
return ret;
}
static VkResult FEXFN_IMPL(vkAllocateMemory)(VkDevice a_0, const VkMemoryAllocateInfo* a_1, const VkAllocationCallbacks* a_2, VkDeviceMemory* a_3) {
(void*&)LDR_PTR(vkAllocateMemory) = (void*)LDR_PTR(vkGetDeviceProcAddr)(a_0, "vkAllocateMemory");
return LDR_PTR(vkAllocateMemory)(a_0, a_1, nullptr, a_3);
}
static void FEXFN_IMPL(vkFreeMemory)(VkDevice a_0, VkDeviceMemory a_1, const VkAllocationCallbacks* a_2) {
(void*&)LDR_PTR(vkFreeMemory) = (void*)LDR_PTR(vkGetDeviceProcAddr)(a_0, "vkFreeMemory");
LDR_PTR(vkFreeMemory)(a_0, a_1, nullptr);
}
static VkResult FEXFN_IMPL(vkCreateDebugReportCallbackEXT)(VkInstance a_0, guest_layout<const VkDebugReportCallbackCreateInfoEXT*> a_1,
const VkAllocationCallbacks* a_2, VkDebugReportCallbackEXT* a_3) {
auto overridden_callback = host_layout<VkDebugReportCallbackCreateInfoEXT> {*a_1.get_pointer()}.data;
overridden_callback.pfnCallback = DummyVkDebugReportCallback;
(void*&)LDR_PTR(vkCreateDebugReportCallbackEXT) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, "vkCreateDebugReportCallbackEXT");
return LDR_PTR(vkCreateDebugReportCallbackEXT)(a_0, &overridden_callback, nullptr, a_3);
}
static void FEXFN_IMPL(vkDestroyDebugReportCallbackEXT)(VkInstance a_0, VkDebugReportCallbackEXT a_1, const VkAllocationCallbacks* a_2) {
(void*&)LDR_PTR(vkDestroyDebugReportCallbackEXT) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, "vkDestroyDebugReportCallbackEXT");
LDR_PTR(vkDestroyDebugReportCallbackEXT)(a_0, a_1, nullptr);
}
extern "C" VkBool32 DummyVkDebugUtilsMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
const VkDebugUtilsMessengerCallbackDataEXT*, void*) {
return VK_FALSE;
}
static VkResult FEXFN_IMPL(vkCreateDebugUtilsMessengerEXT)(VkInstance_T* a_0, guest_layout<const VkDebugUtilsMessengerCreateInfoEXT*> a_1,
const VkAllocationCallbacks* a_2, VkDebugUtilsMessengerEXT* a_3) {
auto overridden_callback = host_layout<VkDebugUtilsMessengerCreateInfoEXT> {*a_1.get_pointer()}.data;
overridden_callback.pfnUserCallback = DummyVkDebugUtilsMessengerCallback;
(void*&)LDR_PTR(vkCreateDebugUtilsMessengerEXT) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, "vkCreateDebugUtilsMessengerEXT");
return LDR_PTR(vkCreateDebugUtilsMessengerEXT)(a_0, &overridden_callback, nullptr, a_3);
}
static PFN_vkVoidFunction LookupCustomVulkanFunction(const char* a_1) {
using namespace std::string_view_literals;
if (a_1 == "vkCreateShaderModule"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkCreateShaderModule;
} else if (a_1 == "vkCreateInstance"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkCreateInstance;
} else if (a_1 == "vkCreateDevice"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkCreateDevice;
} else if (a_1 == "vkAllocateMemory"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkAllocateMemory;
} else if (a_1 == "vkFreeMemory"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkFreeMemory;
} else if (a_1 == "vkAcquireXlibDisplayEXT"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkAcquireXlibDisplayEXT;
} else if (a_1 == "vkGetRandROutputDisplayEXT"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkGetRandROutputDisplayEXT;
} else if (a_1 == "vkGetPhysicalDeviceXcbPresentationSupportKHR"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkGetPhysicalDeviceXcbPresentationSupportKHR;
} else if (a_1 == "vkGetPhysicalDeviceXlibPresentationSupportKHR"sv) {
return (PFN_vkVoidFunction)fexfn_impl_libvulkan_vkGetPhysicalDeviceXlibPresentationSupportKHR;
}
return nullptr;
}
static PFN_vkVoidFunction FEXFN_IMPL(vkGetDeviceProcAddr)(VkDevice a_0, const char* a_1) {
// Just return the host facing function pointer
// The guest will handle mapping if this exists
// Check for functions with custom implementations first
if (auto ptr = LookupCustomVulkanFunction(a_1)) {
return ptr;
}
return LDR_PTR(vkGetDeviceProcAddr)(a_0, a_1);
}
static PFN_vkVoidFunction FEXFN_IMPL(vkGetInstanceProcAddr)(VkInstance a_0, const char* a_1) {
// Just return the host facing function pointer
// The guest will handle mapping if it exists
if (!SetupInstance && a_0) {
DoSetupWithInstance(a_0);
}
// Check for functions with custom implementations first
if (auto ptr = LookupCustomVulkanFunction(a_1)) {
// If this function belongs to an instance extension, requery its address.
// This ensures fexldr_ptr_* is valid if the application creates a minimal
// VkInstance with no extensions before creating its actual instance.
using namespace std::string_view_literals;
if (a_1 == "vkGetRandROutputDisplayEXT"sv && !LDR_PTR(vkGetRandROutputDisplayEXT)) {
(void*&)LDR_PTR(vkGetRandROutputDisplayEXT) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, "vkGetRandROutputDisplayEXT");
}
if (a_1 == "vkAcquireXlibDisplayEXT"sv && !LDR_PTR(vkAcquireXlibDisplayEXT)) {
(void*&)LDR_PTR(vkAcquireXlibDisplayEXT) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, "vkAcquireXlibDisplayEXT");
}
const char* XcbPresent = "vkGetPhysicalDeviceXcbPresentationSupportKHR";
if (a_1 == std::string_view {XcbPresent} && !LDR_PTR(vkGetPhysicalDeviceXcbPresentationSupportKHR)) {
(void*&)LDR_PTR(vkGetPhysicalDeviceXcbPresentationSupportKHR) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, XcbPresent);
}
const char* XlibPresent = "vkGetPhysicalDeviceXlibPresentationSupportKHR";
if (a_1 == std::string_view {XlibPresent} && !LDR_PTR(vkGetPhysicalDeviceXlibPresentationSupportKHR)) {
(void*&)LDR_PTR(vkGetPhysicalDeviceXlibPresentationSupportKHR) = (void*)LDR_PTR(vkGetInstanceProcAddr)(a_0, XlibPresent);
}
return ptr;
}
return LDR_PTR(vkGetInstanceProcAddr)(a_0, a_1);
}
EXPORTS(libvulkan)