mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 15:00:17 +02:00
Merge pull request #5536 from Sonicadvance1/105
LibraryForwarding: Implement support for CUDA
This commit is contained in:
8 files changed
+2781
No files matched your search
@@ -46,6 +46,13 @@
|
||||
"@PREFIX_LIB@/libwayland-client.so.0",
|
||||
"@PREFIX_LIB@/libwayland-client.so.0.20.0"
|
||||
]
|
||||
},
|
||||
"cuda": {
|
||||
"Library" : "libcuda-guest.so",
|
||||
"Overlay": [
|
||||
"@PREFIX_LIB@/libcuda.so",
|
||||
"@PREFIX_LIB@/libcuda.so.1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,3 +266,6 @@ add_library(PlaceholderX11 SHARED ../libX11/libX11_NativeGuest.cpp)
|
||||
target_link_options(PlaceholderX11 PRIVATE "LINKER:-soname,libX11.so.6")
|
||||
set_target_properties(PlaceholderX11 PROPERTIES NO_SONAME ON)
|
||||
target_link_libraries(GL-guest PRIVATE PlaceholderX11)
|
||||
|
||||
generate(libcuda ${CMAKE_CURRENT_SOURCE_DIR}/../libcuda/libcuda_interface.cpp)
|
||||
add_guest_lib(cuda "libcuda.so.1")
|
||||
@@ -167,6 +167,9 @@ foreach(GUEST_BITNESS IN LISTS BITNESS_LIST)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(GL-host-${GUEST_BITNESS} PRIVATE OpenGL::GL)
|
||||
|
||||
generate(libcuda ${CMAKE_CURRENT_SOURCE_DIR}/../libcuda/libcuda_interface.cpp ${GUEST_BITNESS})
|
||||
add_host_lib(cuda ${GUEST_BITNESS})
|
||||
endforeach()
|
||||
|
||||
if (BUILD_FEX_LINUX_TESTS)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*CUhostFn)(void*);
|
||||
enum cudaError_enum {};
|
||||
enum CUgreenCtxCreate_flags {};
|
||||
enum CUdevResourceType {};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "common/Guest.h"
|
||||
#include "cuda_defines.h"
|
||||
|
||||
#include "thunkgen_guest_libcuda.inl"
|
||||
#include <cstdio>
|
||||
#include <dlfcn.h>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Maps cuda API function names to the address of a guest function which is
|
||||
// linked to the corresponding host function pointer
|
||||
const std::unordered_map<std::string_view, uintptr_t /* guest function address */> HostPtrInvokers = std::invoke([]() {
|
||||
#define PAIR(name, unused) Ret[#name] = reinterpret_cast<uintptr_t>(GetCallerForHostFunction(name));
|
||||
std::unordered_map<std::string_view, uintptr_t> Ret;
|
||||
FOREACH_internal_SYMBOL(PAIR);
|
||||
return Ret;
|
||||
#undef PAIR
|
||||
});
|
||||
|
||||
extern "C" {
|
||||
|
||||
// This variable controls the behavior of cuGetProcAddress 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 CUDA functions
|
||||
[[noreturn]]
|
||||
static void FatalError(void* raw_args) {
|
||||
auto called_function = reinterpret_cast<PackedArguments<void, uintptr_t>*>(raw_args)->a0;
|
||||
fprintf(stderr, "FATAL: Called unknown CUDA function at address %p\n", reinterpret_cast<void*>(called_function));
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
static void* MakeGuestCallable(const char* origin, void* func, const char* name) {
|
||||
auto It = HostPtrInvokers.find(name);
|
||||
if (It == HostPtrInvokers.end()) {
|
||||
fprintf(stderr, "%s: Unknown cuda function at address %p: %s\n", origin, func, name);
|
||||
if (stub_unknown_functions) {
|
||||
const auto StubHostPtrInvoker = CallHostFunction<FatalError, void>;
|
||||
LinkAddressToFunction((uintptr_t)func, reinterpret_cast<uintptr_t>(StubHostPtrInvoker));
|
||||
return func;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
LinkAddressToFunction((uintptr_t)func, It->second);
|
||||
return func;
|
||||
}
|
||||
|
||||
struct override_entry {
|
||||
std::string_view name;
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
constexpr static std::array<override_entry, 2> proc_override = {
|
||||
{{"cuGetProcAddress", (void*)cuGetProcAddress_v2}, {"cuGetProcAddress_v2", (void*)cuGetProcAddress_v2}}};
|
||||
|
||||
CUresult cuGetProcAddress_v2(const char* symbol, void** pfn, int cudaVersion, cuuint64_t flags, CUdriverProcAddressQueryResult* symbolStatus) {
|
||||
|
||||
for (auto& over : proc_override) {
|
||||
if (symbol == over.name) {
|
||||
*pfn = over.ptr;
|
||||
if (symbolStatus) {
|
||||
*symbolStatus = (CUdriverProcAddressQueryResult)0;
|
||||
}
|
||||
return (CUresult)0; // CUDA_SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
void* ptr {};
|
||||
auto Ret = fexfn_pack_cuGetProcAddress_v2(symbol, &ptr, cudaVersion, flags, symbolStatus);
|
||||
|
||||
if (!Ret) {
|
||||
*pfn = MakeGuestCallable(__FUNCTION__, ptr, symbol);
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
}
|
||||
|
||||
LOAD_LIB(libcuda)
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "common/Host.h"
|
||||
#include "cuda_defines.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include "thunkgen_host_libcuda.inl"
|
||||
|
||||
#define FEXFN_IMPL(fn) fexfn_impl_libcuda_##fn
|
||||
#define LDR_PTR(fn) fexldr_ptr_libcuda_##fn
|
||||
|
||||
struct override_entry {
|
||||
std::string_view name;
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
constexpr static std::array<override_entry, 2> proc_override = {
|
||||
{{"cuCtxCreate_v2", (void*)FEXFN_IMPL(cuCtxCreate_v2)}, {"cuGetExportTable", (void*)FEXFN_IMPL(cuGetExportTable)}}};
|
||||
|
||||
static CUresult FEXFN_IMPL(cuGetProcAddress_v2)(const char* symbol, guest_layout<void**> pfn, int cudaVersion, cuuint64_t flags,
|
||||
CUdriverProcAddressQueryResult* symbolStatus) {
|
||||
host_layout<void*> host_data {};
|
||||
void* ptr {};
|
||||
CUresult ret {};
|
||||
for (auto& over : proc_override) {
|
||||
if (symbol == over.name) {
|
||||
ptr = over.ptr;
|
||||
if (symbolStatus) {
|
||||
*symbolStatus = (CUdriverProcAddressQueryResult)0; // CU_GET_PROC_ADDRESS_SUCCESS
|
||||
}
|
||||
ret = (CUresult)0; // CUDA_SUCCESS
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
ret = LDR_PTR(cuGetProcAddress_v2)(symbol, &ptr, cudaVersion, flags, symbolStatus);
|
||||
}
|
||||
|
||||
host_data.data = ptr;
|
||||
*pfn.get_pointer() = to_guest(host_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CUresult FEXFN_IMPL(cuCtxCreate_v2)(guest_layout<CUcontext*> pctx, unsigned int flags, CUdevice dev) {
|
||||
host_layout<CUcontext> host_data {};
|
||||
CUcontext ctx;
|
||||
auto ret = LDR_PTR(cuCtxCreate_v2)(&ctx, flags, dev);
|
||||
host_data.data = ctx;
|
||||
*pctx.get_pointer() = to_guest(host_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CUresult FEXFN_IMPL(cuGetExportTable)(guest_layout<const void**> ppExportTable, const CUuuid* pExportTableId) {
|
||||
// This function returns a pointer to an driver internal export table that is undocumented publicly.
|
||||
//
|
||||
// Some documentation about the UUIDs that has been reversed.
|
||||
// https://github.com/vosen/ZLUDA/blob/1b9ba2b2333746c5e2b05a2bf24fa6ec3828dcdf/zluda_dark_api/src/lib.rs#L197
|
||||
//
|
||||
// These two UUIDs are required by the static cuda runtime at startup. Might require more but it currently halts without these
|
||||
// implemented. UUID: [0x6b, 0xd5, 0xfb, 0x6c, 0x5b, 0xf4, 0xe7, 0x4a, 0x89, 0x87, 0xd9, 0x39, 0x12, 0xfd, 0x9d, 0xf9]
|
||||
// - cudart interface (0x68 bytes?)
|
||||
// UUID: [0xa0, 0x94, 0x79, 0x8c, 0x2e, 0x74, 0x2e, 0x74, 0x93, 0xf2, 0x08, 0x00, 0x20, 0x0c, 0x0a, 0x66]
|
||||
// - Tools runtime callback hooks (0x38 bytes?)
|
||||
|
||||
std::string uuid {};
|
||||
for (size_t i = 0; i < sizeof(CUuuid); ++i) {
|
||||
const bool last = (i + 1) == sizeof(CUuuid);
|
||||
char tmp[8];
|
||||
auto size = snprintf(tmp, 8, "0x%02x%s", pExportTableId->_0[i], last ? "" : ", ");
|
||||
uuid += std::string_view(tmp, size);
|
||||
}
|
||||
fprintf(stderr, "cuGetExportTable not implemented\n");
|
||||
fprintf(stderr, "UUID: %s\n", uuid.c_str());
|
||||
return (CUresult)4; // CUDA_ERROR_DEINITIALIZED
|
||||
}
|
||||
|
||||
EXPORTS(libcuda)
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user