Skip to content

Commit

Permalink
Merge pull request #3584 from neobrain/feature_libfwd_guestx11
Browse files Browse the repository at this point in the history
Library Forwarding: Support libGL/libvulkan without forwarding libX11
  • Loading branch information
Sonicadvance1 authored May 2, 2024
2 parents 9781b95 + a15ed4c commit b33e0e3
Show file tree
Hide file tree
Showing 45 changed files with 548 additions and 14,350 deletions.
9 changes: 0 additions & 9 deletions Data/ThunksDB.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
"DB": {
"GL": {
"Library" : "libGL-guest.so",
"Depends": [
"X11"
],
"Overlay": [
"@PREFIX_LIB@/libGL.so",
"@PREFIX_LIB@/libGL.so.1",
Expand Down Expand Up @@ -33,16 +30,10 @@
},
"Vulkan": {
"Library": "libvulkan-guest.so",
"Depends": [
"xcb"
],
"Overlay": [
"@PREFIX_LIB@/libvulkan.so",
"@PREFIX_LIB@/libvulkan.so.1",
"@HOME@/.local/share/Steam/ubuntu12_32/steam-runtime/pinned_libs_64/libvulkan.so.1"
],
"Comment": [
"Vulkan library relies on xcb, otherwise it crashes with jemalloc"
]
},
"xcb": {
Expand Down
25 changes: 16 additions & 9 deletions ThunkLibs/Generator/analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,20 +240,23 @@ void AnalysisAction::ParseInterface(clang::ASTContext& context) {
assert(template_args.size() == 3);

auto function = llvm::dyn_cast<clang::FunctionDecl>(template_args[0].getAsDecl());
auto param_idx = template_args[1].getAsIntegral().getZExtValue();
auto param_idx = template_args[1].getAsIntegral().getSExtValue();
clang::QualType type = context.getCanonicalType(template_args[2].getAsType());
type = type->getLocallyUnqualifiedSingleStepDesugaredType();

if (param_idx >= function->getNumParams()) {
if (param_idx >= function->getNumParams() || param_idx < -1) {
throw report_error(decl->getTypeAsWritten()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getArgLoc(1).getLocation(),
"Out-of-bounds parameter index passed to fex_gen_param");
}

if (!type->isVoidType() && !context.hasSameType(type, function->getParamDecl(param_idx)->getType())) {
auto expected_type = param_idx == -1 ? function->getReturnType() : function->getParamDecl(param_idx)->getType();

if (!type->isVoidType() && !context.hasSameType(type, expected_type)) {
auto loc = param_idx == -1 ? function->getReturnTypeSourceRange().getBegin() :
function->getParamDecl(param_idx)->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
throw report_error(decl->getTypeAsWritten()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getArgLoc(2).getLocation(),
"Type passed to fex_gen_param doesn't match the function signature")
.addNote(report_error(function->getParamDecl(param_idx)->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), "Expected this type "
"instead"));
.addNote(report_error(loc, "Expected this type instead"));
}

param_annotations[function][param_idx] = GetParameterAnnotations(context, decl);
Expand Down Expand Up @@ -366,6 +369,9 @@ void AnalysisAction::ParseInterface(clang::ASTContext& context) {
continue;
}

if (data.param_annotations[param_idx].is_passthrough && !data.custom_host_impl) {
throw report_error(param_loc, "Passthrough annotation requires custom host implementation");
}
// Skip pointers-to-structs passed through to the host in guest_layout.
// This avoids pulling in member types that can't be processed.
if (data.param_annotations[param_idx].is_passthrough && param_type->isPointerType() &&
Expand Down Expand Up @@ -399,6 +405,7 @@ void AnalysisAction::ParseInterface(clang::ASTContext& context) {
if (param_type->isFunctionPointerType()) {
if (param_idx == retval_index) {
// TODO: We already rely on this in a few places...
// TODO: Revisit now that we support ptr_passthrough for return values
// throw report_error(template_arg_loc, "Support for returning function pointers is not implemented");
continue;
}
Expand Down Expand Up @@ -460,10 +467,6 @@ void AnalysisAction::ParseInterface(clang::ASTContext& context) {
check_struct_type(pointee_type.getTypePtr());
types.emplace(context.getCanonicalType(pointee_type.getTypePtr()), RepackedType {});
} else if (data.param_annotations[param_idx].is_passthrough) {
if (!data.custom_host_impl) {
throw report_error(param_loc, "Passthrough annotation requires custom host implementation");
}

// Nothing to do
} else if (false /* TODO: Can't check if this is unsupported until data layout analysis is complete */) {
throw report_error(param_loc, "Unsupported parameter type")
Expand Down Expand Up @@ -542,6 +545,10 @@ void AnalysisAction::CoverReferencedTypes(clang::ASTContext& context) {

for (auto* member : type->getAsStructureType()->getDecl()->fields()) {
auto member_type = member->getType().getTypePtr();
if (type_repack_info.UsesCustomRepackFor(member) && member_type->isPointerType() && member_type->getPointeeType()->isStructureType()) {
continue;
}

while (member_type->isArrayType()) {
member_type = member_type->getArrayElementTypeNoTypeQual();
}
Expand Down
14 changes: 8 additions & 6 deletions ThunkLibs/Generator/gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,13 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {
if (thunk.param_annotations[idx].is_passthrough) {
fmt::print(file, "guest_layout<{}> a_{}", get_guest_type_name(type), idx);
} else {
file << format_decl(type, fmt::format("a_{}", idx));
fmt::print(file, "{}", format_decl(type, fmt::format("a_{}", idx)));
}
}
// Using trailing return type as it makes handling function pointer returns much easier
file << ") -> " << thunk.return_type.getAsString() << ";\n";
bool is_passthrough_ret = thunk.param_annotations[-1].is_passthrough;
fmt::print(file, ") -> {}{}{};\n", is_passthrough_ret ? "guest_layout<" : "", thunk.return_type.getAsString(),
is_passthrough_ret ? ">" : "");
}

// Check data layout compatibility of parameter types
Expand Down Expand Up @@ -676,7 +678,7 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {

if (!thunk.return_type->isVoidType()) {
fmt::print(file, " args->rv = ");
if (!thunk.return_type->isFunctionPointerType()) {
if (!thunk.return_type->isFunctionPointerType() && !thunk.param_annotations[-1].is_passthrough) {
fmt::print(file, "to_guest(to_host_layout<{}>(", thunk.return_type.getAsString());
}
}
Expand Down Expand Up @@ -707,7 +709,7 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {

fmt::print(file, "{}", format_function_args(thunk, format_param));
}
if (!thunk.return_type->isVoidType() && !thunk.return_type->isFunctionPointerType()) {
if (!thunk.return_type->isVoidType() && !thunk.return_type->isFunctionPointerType() && !thunk.param_annotations[-1].is_passthrough) {
fmt::print(file, "))");
}
fmt::print(file, ");\n");
Expand Down Expand Up @@ -746,8 +748,8 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {
}

std::string annotations;
for (int param_idx = 0; param_idx < info.args.size(); ++param_idx) {
if (param_idx != 0) {
for (int param_idx = -1; param_idx < (int)info.args.size(); ++param_idx) {
if (param_idx != -1) {
annotations += ", ";
}

Expand Down
62 changes: 0 additions & 62 deletions ThunkLibs/GuestLibs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,72 +195,10 @@ if (BITNESS EQUAL 64)
# target_link_libraries(SDL2-guest PRIVATE GL)
# target_link_libraries(SDL2-guest PRIVATE dl)

find_package(PkgConfig)
pkg_search_module(X11 REQUIRED x11)
version_to_variables(${X11_VERSION} X11)

generate(libX11 ${CMAKE_CURRENT_SOURCE_DIR}/../libX11/libX11_interface.cpp)
add_guest_lib(X11 "libX11.so.6")

target_compile_definitions(libX11-guest-deps INTERFACE -DX11_VERSION_MAJOR=${X11_VERSION_MAJOR})
target_compile_definitions(libX11-guest-deps INTERFACE -DX11_VERSION_MINOR=${X11_VERSION_MINOR})
target_compile_definitions(libX11-guest-deps INTERFACE -DX11_VERSION_PATCH=${X11_VERSION_PATCH})

generate(libXext ${CMAKE_CURRENT_SOURCE_DIR}/../libXext/libXext_interface.cpp)
add_guest_lib(Xext "libXext.so.6")

target_compile_definitions(libXext-guest-deps INTERFACE -DX11_VERSION_MAJOR=${X11_VERSION_MAJOR})
target_compile_definitions(libXext-guest-deps INTERFACE -DX11_VERSION_MINOR=${X11_VERSION_MINOR})
target_compile_definitions(libXext-guest-deps INTERFACE -DX11_VERSION_PATCH=${X11_VERSION_PATCH})

generate(libXrender ${CMAKE_CURRENT_SOURCE_DIR}/../libXrender/libXrender_interface.cpp)
add_guest_lib(Xrender "libXrender.so.1")

generate(libXfixes ${CMAKE_CURRENT_SOURCE_DIR}/../libXfixes/libXfixes_interface.cpp)
add_guest_lib(Xfixes "libXfixes.so.3")

generate(libvulkan ${CMAKE_CURRENT_SOURCE_DIR}/../libvulkan/libvulkan_interface.cpp)
target_include_directories(libvulkan-guest-deps INTERFACE ${FEX_PROJECT_SOURCE_DIR}/External/Vulkan-Headers/include/)
add_guest_lib(vulkan "libvulkan.so.1")

find_package(PkgConfig)
pkg_search_module(XCB REQUIRED xcb)
version_to_variables(${XCB_VERSION} XCB)

generate(libxcb ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb/libxcb_interface.cpp)
add_guest_lib(xcb "libxcb.so.1")

target_compile_definitions(libxcb-guest-deps INTERFACE -DXCB_VERSION_MAJOR=${XCB_VERSION_MAJOR})
target_compile_definitions(libxcb-guest-deps INTERFACE -DXCB_VERSION_MINOR=${XCB_VERSION_MINOR})
target_compile_definitions(libxcb-guest-deps INTERFACE -DXCB_VERSION_PATCH=${XCB_VERSION_PATCH})

generate(libxcb-dri2 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri2/libxcb-dri2_interface.cpp)
add_guest_lib(xcb-dri2 "libxcb-dri2.so.0")

generate(libxcb-dri3 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri3/libxcb-dri3_interface.cpp)
add_guest_lib(xcb-dri3 "libxcb-dri3.so.0")

generate(libxcb-xfixes ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-xfixes/libxcb-xfixes_interface.cpp)
add_guest_lib(xcb-xfixes "libxcb-xfixes.so.0")

generate(libxcb-shm ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-shm/libxcb-shm_interface.cpp)
add_guest_lib(xcb-shm "libxcb-shm.so.0")

generate(libxcb-sync ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-sync/libxcb-sync_interface.cpp)
add_guest_lib(xcb-sync "libxcb-sync.so.1")

generate(libxcb-present ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-present/libxcb-present_interface.cpp)
add_guest_lib(xcb-present "libxcb-present.so.0")

generate(libxcb-randr ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-randr/libxcb-randr_interface.cpp)
add_guest_lib(xcb-randr "libxcb-randr.so.0")

generate(libxcb-glx ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-glx/libxcb-glx_interface.cpp)
add_guest_lib(xcb-glx "libxcb-glx.so.0")

generate(libxshmfence ${CMAKE_CURRENT_SOURCE_DIR}/../libxshmfence/libxshmfence_interface.cpp)
add_guest_lib(xshmfence "libxshmfence.so.1")

generate(libdrm ${CMAKE_CURRENT_SOURCE_DIR}/../libdrm/libdrm_interface.cpp)
target_include_directories(libdrm-guest-deps INTERFACE /usr/include/drm/)
target_include_directories(libdrm-guest-deps INTERFACE /usr/include/libdrm/)
Expand Down
62 changes: 0 additions & 62 deletions ThunkLibs/HostLibs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,72 +124,10 @@ foreach(GUEST_BITNESS IN LISTS BITNESS_LIST)
# add_host_lib(SDL2 ${GUEST_BITNESS})
# target_include_directories(SDL2-host PRIVATE ${SDL2_INCLUDE_DIRS})

find_package(PkgConfig)
pkg_search_module(X11 REQUIRED x11)
version_to_variables(${X11_VERSION} X11)

generate(libX11 ${CMAKE_CURRENT_SOURCE_DIR}/../libX11/libX11_interface.cpp ${GUEST_BITNESS})
add_host_lib(X11 ${GUEST_BITNESS})

target_compile_definitions(libX11-${GUEST_BITNESS}-deps INTERFACE -DX11_VERSION_MAJOR=${X11_VERSION_MAJOR})
target_compile_definitions(libX11-${GUEST_BITNESS}-deps INTERFACE -DX11_VERSION_MINOR=${X11_VERSION_MINOR})
target_compile_definitions(libX11-${GUEST_BITNESS}-deps INTERFACE -DX11_VERSION_PATCH=${X11_VERSION_PATCH})

generate(libXext ${CMAKE_CURRENT_SOURCE_DIR}/../libXext/libXext_interface.cpp ${GUEST_BITNESS})
add_host_lib(Xext ${GUEST_BITNESS})

target_compile_definitions(libXext-${GUEST_BITNESS}-deps INTERFACE -DX11_VERSION_MAJOR=${X11_VERSION_MAJOR})
target_compile_definitions(libXext-${GUEST_BITNESS}-deps INTERFACE -DX11_VERSION_MINOR=${X11_VERSION_MINOR})
target_compile_definitions(libXext-${GUEST_BITNESS}-deps INTERFACE -DX11_VERSION_PATCH=${X11_VERSION_PATCH})

generate(libXrender ${CMAKE_CURRENT_SOURCE_DIR}/../libXrender/libXrender_interface.cpp ${GUEST_BITNESS})
add_host_lib(Xrender ${GUEST_BITNESS})

generate(libXfixes ${CMAKE_CURRENT_SOURCE_DIR}/../libXfixes/libXfixes_interface.cpp ${GUEST_BITNESS})
add_host_lib(Xfixes ${GUEST_BITNESS})

generate(libvulkan ${CMAKE_CURRENT_SOURCE_DIR}/../libvulkan/libvulkan_interface.cpp ${GUEST_BITNESS})
target_include_directories(libvulkan-${GUEST_BITNESS}-deps INTERFACE ${FEX_PROJECT_SOURCE_DIR}/External/Vulkan-Headers/include/)
add_host_lib(vulkan ${GUEST_BITNESS})

find_package(PkgConfig)
pkg_search_module(XCB REQUIRED xcb)
version_to_variables(${XCB_VERSION} XCB)

generate(libxcb ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb/libxcb_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb ${GUEST_BITNESS})

target_compile_definitions(libxcb-${GUEST_BITNESS}-deps INTERFACE -DXCB_VERSION_MAJOR=${XCB_VERSION_MAJOR})
target_compile_definitions(libxcb-${GUEST_BITNESS}-deps INTERFACE -DXCB_VERSION_MINOR=${XCB_VERSION_MINOR})
target_compile_definitions(libxcb-${GUEST_BITNESS}-deps INTERFACE -DXCB_VERSION_PATCH=${XCB_VERSION_PATCH})

generate(libxcb-dri2 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri2/libxcb-dri2_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-dri2 ${GUEST_BITNESS})

generate(libxcb-dri3 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri3/libxcb-dri3_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-dri3 ${GUEST_BITNESS})

generate(libxcb-xfixes ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-xfixes/libxcb-xfixes_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-xfixes ${GUEST_BITNESS})

generate(libxcb-shm ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-shm/libxcb-shm_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-shm ${GUEST_BITNESS})

generate(libxcb-sync ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-sync/libxcb-sync_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-sync ${GUEST_BITNESS})

generate(libxcb-present ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-present/libxcb-present_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-present ${GUEST_BITNESS})

generate(libxcb-randr ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-randr/libxcb-randr_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-randr ${GUEST_BITNESS})

generate(libxcb-glx ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-glx/libxcb-glx_interface.cpp ${GUEST_BITNESS})
add_host_lib(xcb-glx ${GUEST_BITNESS})

generate(libxshmfence ${CMAKE_CURRENT_SOURCE_DIR}/../libxshmfence/libxshmfence_interface.cpp ${GUEST_BITNESS})
add_host_lib(xshmfence ${GUEST_BITNESS})

generate(libdrm ${CMAKE_CURRENT_SOURCE_DIR}/../libdrm/libdrm_interface.cpp ${GUEST_BITNESS})
target_include_directories(libdrm-${GUEST_BITNESS}-deps INTERFACE /usr/include/drm/)
target_include_directories(libdrm-${GUEST_BITNESS}-deps INTERFACE /usr/include/libdrm/)
Expand Down
36 changes: 29 additions & 7 deletions ThunkLibs/include/common/Host.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,12 +466,22 @@ constexpr bool IsCompatible() {
}
}

template<typename T>
struct decaying_host_layout {
host_layout<T> data;
operator T() {
return data.data;
}
};

template<ParameterAnnotations Annotation, typename HostT, typename T>
auto Projection(guest_layout<T>& data) {
if constexpr (Annotation.is_passthrough) {
return data;
} else if constexpr ((IsCompatible<T, Annotation>() && std::is_same_v<T, HostT>) || !std::is_pointer_v<T>) {
return host_layout<HostT> {data}.data;
// Instead of using host_layout<HostT> { data }.data, return a wrapper object.
// This ensures that temporary lifetime extension can kick in at call-site.
return decaying_host_layout<HostT> {.data {data}};
} else {
// This argument requires temporary storage for repacked data
// *and* it needs to call custom repack functions (if any)
Expand Down Expand Up @@ -526,19 +536,23 @@ struct CallbackUnpack<Result(Args...)> {
}
};

template<bool Cond, typename T>
using as_guest_layout_if = std::conditional_t<Cond, guest_layout<T>, T>;

template<typename, typename...>
struct GuestWrapperForHostFunction;

template<typename Result, typename... Args, typename... GuestArgs>
struct GuestWrapperForHostFunction<Result(Args...), GuestArgs...> {
// Host functions called from Guest
// NOTE: GuestArgs typically matches up with Args, however there may be exceptions (e.g. size_t)
template<ParameterAnnotations... Annotations>
template<ParameterAnnotations RetAnnotations, ParameterAnnotations... Annotations>
static void Call(void* argsv) {
static_assert(sizeof...(Annotations) == sizeof...(Args));
static_assert(sizeof...(GuestArgs) == sizeof...(Args));

auto args = reinterpret_cast<PackedArguments<Result, guest_layout<GuestArgs>..., uintptr_t>*>(argsv);
auto args =
reinterpret_cast<PackedArguments<as_guest_layout_if<!std::is_void_v<Result>, Result>, guest_layout<GuestArgs>..., uintptr_t>*>(argsv);
constexpr auto CBIndex = sizeof...(GuestArgs);
uintptr_t cb;
static_assert(CBIndex <= 18 || CBIndex == 23);
Expand Down Expand Up @@ -585,12 +599,20 @@ struct GuestWrapperForHostFunction<Result(Args...), GuestArgs...> {
}

// This is almost the same type as "Result func(Args..., uintptr_t)", but
// individual parameters annotated as passthrough are replaced by guest_layout<GuestArgs>
auto callback = reinterpret_cast<Result (*)(std::conditional_t<Annotations.is_passthrough, guest_layout<GuestArgs>, Args>..., uintptr_t)>(cb);
// individual types annotated as passthrough are wrapped in guest_layout<>
auto callback =
reinterpret_cast<as_guest_layout_if<RetAnnotations.is_passthrough, Result> (*)(as_guest_layout_if<Annotations.is_passthrough, Args>..., uintptr_t)>(
cb);

auto f = [&callback](guest_layout<GuestArgs>... args, uintptr_t target) -> Result {
auto f = [&callback](guest_layout<GuestArgs>... args, uintptr_t target) {
// Fold over each of Annotations, Args, and args. This will match up the elements in triplets.
return callback(Projection<Annotations, Args>(args)..., target);
if constexpr (std::is_void_v<Result>) {
callback(Projection<Annotations, Args>(args)..., target);
} else if constexpr (!RetAnnotations.is_passthrough) {
return (guest_layout<Result>)to_guest(to_host_layout(callback(Projection<Annotations, Args>(args)..., target)));
} else {
return callback(Projection<Annotations, Args>(args)..., target);
}
};
Invoke(f, *args);
}
Expand Down
Loading

0 comments on commit b33e0e3

Please sign in to comment.