diff --git a/Data/ThunksDB.json b/Data/ThunksDB.json index 4ae9b592a..5128cb413 100644 --- a/Data/ThunksDB.json +++ b/Data/ThunksDB.json @@ -2,9 +2,6 @@ "DB": { "GL": { "Library" : "libGL-guest.so", - "Depends": [ - "X11" - ], "Overlay": [ "@PREFIX_LIB@/libGL.so", "@PREFIX_LIB@/libGL.so.1", diff --git a/ThunkLibs/include/common/Host.h b/ThunkLibs/include/common/Host.h index 0f09ed4e7..b98a6645a 100644 --- a/ThunkLibs/include/common/Host.h +++ b/ThunkLibs/include/common/Host.h @@ -466,12 +466,22 @@ constexpr bool IsCompatible() { } } +template +struct decaying_host_layout { + host_layout data; + operator T() { + return data.data; + } +}; + template auto Projection(guest_layout& data) { if constexpr (Annotation.is_passthrough) { return data; } else if constexpr ((IsCompatible() && std::is_same_v) || !std::is_pointer_v) { - return host_layout {data}.data; + // Instead of using host_layout { data }.data, return a wrapper object. + // This ensures that temporary lifetime extension can kick in at call-site. + return decaying_host_layout {.data {data}}; } else { // This argument requires temporary storage for repacked data // *and* it needs to call custom repack functions (if any) diff --git a/ThunkLibs/libGL/libGL_Guest.cpp b/ThunkLibs/libGL/libGL_Guest.cpp index 3d09be3f7..1e264a6fa 100644 --- a/ThunkLibs/libGL/libGL_Guest.cpp +++ b/ThunkLibs/libGL/libGL_Guest.cpp @@ -18,6 +18,7 @@ $end_info$ #include #include +#include #include #include #include @@ -72,8 +73,20 @@ voidFunc* glXGetProcAddressARB(const GLubyte* procname) { } } +// Wrapper around malloc() without noexcept specifiers +static void* malloc_wrapper(size_t size) { + return malloc(size); +} + +static void OnInit() { + fexfn_pack_SetGuestMalloc((uintptr_t)malloc_wrapper, (uintptr_t)CallbackUnpack::Unpack); + fexfn_pack_SetGuestXSync((uintptr_t)XSync, (uintptr_t)CallbackUnpack::Unpack); + fexfn_pack_SetGuestXGetVisualInfo((uintptr_t)XGetVisualInfo, (uintptr_t)CallbackUnpack::Unpack); + fexfn_pack_SetGuestXDisplayString((uintptr_t)XDisplayString, (uintptr_t)CallbackUnpack::Unpack); +} + // libGL.so must pull in libX11.so as a dependency. Referencing some libX11 // symbol here prevents the linker from optimizing away the unused dependency auto implicit_libx11_dependency = XSetErrorHandler; -LOAD_LIB(libGL) +LOAD_LIB_INIT(libGL, OnInit) diff --git a/ThunkLibs/libGL/libGL_Host.cpp b/ThunkLibs/libGL/libGL_Host.cpp index aad50da4a..36f8a3f21 100644 --- a/ThunkLibs/libGL/libGL_Host.cpp +++ b/ThunkLibs/libGL/libGL_Host.cpp @@ -6,7 +6,8 @@ $end_info$ */ #include -#include +#include +#include #define GL_GLEXT_PROTOTYPES 1 #define GLX_GLXEXT_PROTOTYPES 1 @@ -17,15 +18,195 @@ $end_info$ #include #include #include - -#include +#include #include "common/Host.h" +#include "common/X11Manager.h" + +template<> +struct host_layout<_XDisplay*> { + _XDisplay* data; + _XDisplay* guest_display; + + host_layout(guest_layout<_XDisplay*>&); + + ~host_layout(); +}; + +static X11Manager x11_manager; + +static void* (*GuestMalloc)(size_t) = nullptr; + +host_layout<_XDisplay*>::host_layout(guest_layout<_XDisplay*>& guest) + : guest_display(guest.force_get_host_pointer()) { + data = x11_manager.GuestToHostDisplay(guest_display); +} + +host_layout<_XDisplay*>::~host_layout() { + // Flush host-side event queue to make effects of the guest-side connection visible + x11_manager.HostXFlush(data); +} + +static void fexfn_impl_libGL_SetGuestMalloc(uintptr_t GuestTarget, uintptr_t GuestUnpacker) { + MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &GuestMalloc); +} + +static void fexfn_impl_libGL_SetGuestXGetVisualInfo(uintptr_t GuestTarget, uintptr_t GuestUnpacker) { + MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &x11_manager.GuestXGetVisualInfo); +} + +static void fexfn_impl_libGL_SetGuestXSync(uintptr_t GuestTarget, uintptr_t GuestUnpacker) { + MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &x11_manager.GuestXSync); +} + +static void fexfn_impl_libGL_SetGuestXDisplayString(uintptr_t GuestTarget, uintptr_t GuestUnpacker) { + MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &x11_manager.GuestXDisplayString); +} #include "thunkgen_host_libGL.inl" -void* symbolFromGlXGetProcAddr(void*, const char* name) { - return (void*)glXGetProcAddress((const GLubyte*)name); +auto fexfn_impl_libGL_glXGetProcAddress(const GLubyte* name) -> void (*)() { + using VoidFn = void (*)(); + std::string_view name_sv {reinterpret_cast(name)}; + if (name_sv == "glXChooseFBConfig") { + return (VoidFn)fexfn_impl_libGL_glXChooseFBConfig; + } else if (name_sv == "glXChooseFBConfigSGIX") { + return (VoidFn)fexfn_impl_libGL_glXChooseFBConfigSGIX; + } else if (name_sv == "glXGetFBConfigs") { + return (VoidFn)fexfn_impl_libGL_glXGetFBConfigs; + } else if (name_sv == "glXGetFBConfigFromVisualSGIX") { + return (VoidFn)fexfn_impl_libGL_glXGetFBConfigFromVisualSGIX; + } else if (name_sv == "glXGetVisualFromFBConfigSGIX") { + return (VoidFn)fexfn_impl_libGL_glXGetVisualFromFBConfigSGIX; + } else if (name_sv == "glXChooseVisual") { + return (VoidFn)fexfn_impl_libGL_glXChooseVisual; + } else if (name_sv == "glXCreateContext") { + return (VoidFn)fexfn_impl_libGL_glXCreateContext; + } else if (name_sv == "glXCreateGLXPixmap") { + return (VoidFn)fexfn_impl_libGL_glXCreateGLXPixmap; + } else if (name_sv == "glXCreateGLXPixmapMESA") { + return (VoidFn)fexfn_impl_libGL_glXCreateGLXPixmapMESA; + } else if (name_sv == "glXGetConfig") { + return (VoidFn)fexfn_impl_libGL_glXGetConfig; + } else if (name_sv == "glXGetVisualFromFBConfig") { + return (VoidFn)fexfn_impl_libGL_glXGetVisualFromFBConfig; + } + return (VoidFn)glXGetProcAddress((const GLubyte*)name); +} + +// Relocate data to guest heap so it can be called with XFree. +// The memory at the given host location will be de-allocated. +template +T* RelocateArrayToGuestHeap(T* Data, int NumItems) { + if (!Data) { + return nullptr; + } + + guest_layout GuestData; + GuestData.data = reinterpret_cast(GuestMalloc(sizeof(guest_layout) * NumItems)); + for (int Index = 0; Index < NumItems; ++Index) { + GuestData.get_pointer()[Index] = to_guest(to_host_layout(Data[Index])); + } + x11_manager.HostXFree(Data); + return GuestData.force_get_host_pointer(); +} + +// Maps to a host-side XVisualInfo, which must be XFree'ed by the caller. +static XVisualInfo* LookupHostVisualInfo(Display* HostDisplay, guest_layout GuestInfo) { + if (!GuestInfo.data) { + return nullptr; + } + + int num_matches; + auto ret = x11_manager.HostXGetVisualInfo(HostDisplay, VisualScreenMask | VisualIDMask, GuestInfo.force_get_host_pointer(), &num_matches); + if (num_matches != 1) { + fprintf(stderr, "ERROR: Did not find unique host XVisualInfo\n"); + std::abort(); + } + return ret; +} + +// Maps to a guest-side XVisualInfo and destroys the host argument. +static guest_layout MapToGuestVisualInfo(Display* HostDisplay, XVisualInfo* HostInfo) { + if (!HostInfo) { + return guest_layout {.data = 0}; + } + + int num_matches; + auto guest_display = x11_manager.HostToGuestDisplay(HostDisplay); + auto ret = x11_manager.GuestXGetVisualInfo(guest_display.get_pointer(), VisualScreenMask | VisualIDMask, HostInfo, &num_matches); + if (num_matches != 1) { + fprintf(stderr, "ERROR: Did not find unique guest XVisualInfo\n"); + std::abort(); + } + + // We effectively relocated the VisualInfo, so free the original one now + x11_manager.HostXFree(HostInfo); + guest_layout GuestRet; + GuestRet.data = reinterpret_cast(ret); + return GuestRet; +} + +GLXFBConfig* fexfn_impl_libGL_glXChooseFBConfig(Display* Display, int Screen, const int* Attributes, int* NumItems) { + auto ret = fexldr_ptr_libGL_glXChooseFBConfig(Display, Screen, Attributes, NumItems); + return RelocateArrayToGuestHeap(ret, *NumItems); +} + +GLXFBConfigSGIX* fexfn_impl_libGL_glXChooseFBConfigSGIX(Display* Display, int Screen, int* Attributes, int* NumItems) { + auto ret = fexldr_ptr_libGL_glXChooseFBConfigSGIX(Display, Screen, Attributes, NumItems); + return RelocateArrayToGuestHeap(ret, *NumItems); +} + +GLXFBConfig* fexfn_impl_libGL_glXGetFBConfigs(Display* Display, int Screen, int* NumItems) { + auto ret = fexldr_ptr_libGL_glXGetFBConfigs(Display, Screen, NumItems); + return RelocateArrayToGuestHeap(ret, *NumItems); +} + +GLXFBConfigSGIX fexfn_impl_libGL_glXGetFBConfigFromVisualSGIX(Display* Display, guest_layout Info) { + auto HostInfo = LookupHostVisualInfo(Display, Info); + auto ret = fexldr_ptr_libGL_glXGetFBConfigFromVisualSGIX(Display, HostInfo); + x11_manager.HostXFree(HostInfo); + return ret; +} + +guest_layout fexfn_impl_libGL_glXGetVisualFromFBConfigSGIX(Display* Display, GLXFBConfigSGIX Config) { + return MapToGuestVisualInfo(Display, fexldr_ptr_libGL_glXGetVisualFromFBConfigSGIX(Display, Config)); +} + +guest_layout fexfn_impl_libGL_glXChooseVisual(Display* Display, int Screen, int* Attributes) { + return MapToGuestVisualInfo(Display, fexldr_ptr_libGL_glXChooseVisual(Display, Screen, Attributes)); +} + +GLXContext fexfn_impl_libGL_glXCreateContext(Display* Display, guest_layout Info, GLXContext ShareList, Bool Direct) { + auto HostInfo = LookupHostVisualInfo(Display, Info); + auto ret = fexldr_ptr_libGL_glXCreateContext(Display, HostInfo, ShareList, Direct); + x11_manager.HostXFree(HostInfo); + return ret; +} + +GLXPixmap fexfn_impl_libGL_glXCreateGLXPixmap(Display* Display, guest_layout Info, Pixmap Pixmap) { + auto HostInfo = LookupHostVisualInfo(Display, Info); + auto ret = fexldr_ptr_libGL_glXCreateGLXPixmap(Display, HostInfo, Pixmap); + x11_manager.HostXFree(HostInfo); + return ret; +} + +GLXPixmap fexfn_impl_libGL_glXCreateGLXPixmapMESA(Display* Display, guest_layout Info, Pixmap Pixmap, Colormap Colormap) { + auto HostInfo = LookupHostVisualInfo(Display, Info); + auto ret = fexldr_ptr_libGL_glXCreateGLXPixmapMESA(Display, HostInfo, Pixmap, Colormap); + x11_manager.HostXFree(HostInfo); + return ret; +} + +int fexfn_impl_libGL_glXGetConfig(Display* Display, guest_layout Info, int Attribute, int* Value) { + auto HostInfo = LookupHostVisualInfo(Display, Info); + auto ret = fexldr_ptr_libGL_glXGetConfig(Display, HostInfo, Attribute, Value); + x11_manager.HostXFree(HostInfo); + return ret; +} + +guest_layout fexfn_impl_libGL_glXGetVisualFromFBConfig(Display* Display, GLXFBConfig Config) { + return MapToGuestVisualInfo(Display, fexldr_ptr_libGL_glXGetVisualFromFBConfig(Display, Config)); } EXPORTS(libGL) diff --git a/ThunkLibs/libGL/libGL_interface.cpp b/ThunkLibs/libGL/libGL_interface.cpp index 856dc2b26..a5a29c907 100644 --- a/ThunkLibs/libGL/libGL_interface.cpp +++ b/ThunkLibs/libGL/libGL_interface.cpp @@ -19,7 +19,21 @@ struct fex_gen_config { }; template<> -struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::returns_guest_pointer {}; +struct fex_gen_config : fexgen::custom_host_impl, fexgen::custom_guest_entrypoint, fexgen::returns_guest_pointer {}; + +// internal use +void SetGuestMalloc(uintptr_t, uintptr_t); +void SetGuestXSync(uintptr_t, uintptr_t); +void SetGuestXGetVisualInfo(uintptr_t, uintptr_t); +void SetGuestXDisplayString(uintptr_t, uintptr_t); +template<> +struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::custom_host_impl {}; +template<> +struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::custom_host_impl {}; +template<> +struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::custom_host_impl {}; +template<> +struct fex_gen_config : fexgen::custom_guest_entrypoint, fexgen::custom_host_impl {}; template struct fex_gen_type {}; @@ -37,21 +51,23 @@ struct fex_gen_type<_cl_context> : fexgen::opaque_type {}; template<> struct fex_gen_type<_cl_event> : fexgen::opaque_type {}; -// Opaque for the purpose of libGL +// host_layout is manually customized for this. Mark as opaque to please the interface parser template<> struct fex_gen_type<_XDisplay> : fexgen::opaque_type {}; -#ifndef IS_32BIT_THUNK -// TODO: These are largely compatible, *but* contain function pointer members that need adjustment! template<> -struct fex_gen_type : fexgen::assume_compatible_data_layout {}; -#endif +struct fex_gen_type : fexgen::emit_layout_wrappers {}; +template<> +struct fex_gen_type : fexgen::opaque_type {}; // Used in XVisualInfo; treat as opaque // Symbols queryable through glXGetProcAddr namespace internal { template struct fex_gen_config : fexgen::generate_guest_symtable, fexgen::indirect_guest_calls {}; +template +struct fex_gen_param {}; + template<> struct fex_gen_config {}; template<> @@ -65,9 +81,11 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; template<> struct fex_gen_config {}; template<> @@ -119,7 +137,9 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; template<> struct fex_gen_config {}; template<> @@ -129,7 +149,9 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; template<> struct fex_gen_config {}; template<> @@ -139,19 +161,23 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; template<> struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; template<> struct fex_gen_config {}; template<> @@ -195,9 +221,13 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; template<> -struct fex_gen_config {}; +struct fex_gen_param : fexgen::ptr_passthrough {}; +template<> +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; // template<> struct fex_gen_config {}; template<> @@ -6179,7 +6209,9 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config : fexgen::custom_host_impl {}; +template<> +struct fex_gen_param : fexgen::ptr_passthrough {}; template<> struct fex_gen_config {}; template<> @@ -6193,7 +6225,7 @@ struct fex_gen_config {}; template<> struct fex_gen_config {}; template<> -struct fex_gen_config {}; +struct fex_gen_config {}; // TODO: Custom host impl template<> struct fex_gen_config {}; template<>