/* $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 #include "common/Guest.h" #include #include #include #include #include #include "thunkgen_guest_libvulkan.inl" extern "C" { // Maps Vulkan API function names to the address of a guest function which is // linked to the corresponding host function pointer const std::unordered_map HostPtrInvokers = std::invoke([]() { #define PAIR(name, unused) Ret[#name] = reinterpret_cast(GetCallerForHostFunction(name)); std::unordered_map Ret; FOREACH_internal_SYMBOL(PAIR); return Ret; #undef PAIR }); // This variable controls the behavior of vkGetDevice/InstanceProcAddr for functions we don't know the signature of: // - if false (default), we return a nullptr (since the application might have a fallback code path) // - if true, we return a stub function that fatally errors upon being called constexpr bool stub_unknown_functions = false; // Fatally erroring function with a thunk-like interface. This is used as a placeholder for unknown Vulkan functions [[noreturn]] static void FatalError(void* raw_args) { auto called_function = reinterpret_cast*>(raw_args)->a0; fprintf(stderr, "FATAL: Called unknown Vulkan function at address %p\n", reinterpret_cast(called_function)); __builtin_trap(); } static PFN_vkVoidFunction MakeGuestCallable(const char* origin, PFN_vkVoidFunction func, const char* name) { auto It = HostPtrInvokers.find(name); if (It == HostPtrInvokers.end()) { fprintf(stderr, "%s: Unknown Vulkan function at address %p: %s\n", origin, func, name); if (stub_unknown_functions) { const auto StubHostPtrInvoker = CallHostFunction; LinkAddressToFunction((uintptr_t)func, reinterpret_cast(StubHostPtrInvoker)); return func; } return nullptr; } fprintf(stderr, "Linking address %p to host invoker %#zx\n", func, It->second); LinkAddressToFunction((uintptr_t)func, It->second); return func; } PFN_vkVoidFunction vkGetDeviceProcAddr(VkDevice a_0, const char* a_1) { auto Ret = fexfn_pack_vkGetDeviceProcAddr(a_0, a_1); if (!Ret) { return nullptr; } return MakeGuestCallable(__FUNCTION__, Ret, a_1); } PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance a_0, const char* a_1) { if (a_1 == std::string_view {"vkGetDeviceProcAddr"}) { return (PFN_vkVoidFunction)vkGetDeviceProcAddr; } else { auto Ret = fexfn_pack_vkGetInstanceProcAddr(a_0, a_1); if (!Ret) { return nullptr; } return MakeGuestCallable(__FUNCTION__, Ret, a_1); } } } void OnInit() { // TODO: Load libX11 on-demand instead void* libx11 = dlopen("libX11.so.6", RTLD_LAZY); fexfn_pack_Vulkan_SetGuestXSync((uintptr_t)dlsym(libx11, "XSync"), (uintptr_t)CallbackUnpack::Unpack); fexfn_pack_Vulkan_SetGuestXGetVisualInfo((uintptr_t)dlsym(libx11, "XGetVisualInfo"), (uintptr_t)CallbackUnpack::Unpack); fexfn_pack_Vulkan_SetGuestXDisplayString((uintptr_t)dlsym(libx11, "XDisplayString"), (uintptr_t)CallbackUnpack::Unpack); } LOAD_LIB_INIT(libvulkan, OnInit)