/* $info$ tags: thunklibs|GL desc: Uses glXGetProcAddress instead of dlsym $end_info$ */ #include #include #include #define GL_GLEXT_PROTOTYPES 1 #define GLX_GLXEXT_PROTOTYPES 1 #include "glcorearb.h" #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" 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)