Add workaround for when vulkan ICD is libGL.so and we repoint it to us

* Some distribution packages (Ubuntu at least I think) point the nvidia
  vulkan ICD registration at libGL.so. Since for libGL hooking we have
  to redirect dlopen("libGL.so") to ourselves, this means the vulkan
  loader loads librenderdoc instead of libGL. If we don't export the VK
  ICD entry points, it will fail to load that ICD.
* This solution isn't perfect - we export all three main ICD entry
  points. If the real ICD doesn't export one, we will fail and cause
  problems, since the loader won't fall back to older paths unless the
  symbol is completely missing. For now though this is fine since the
  nvidia ICD exports all three.
* The only way to solve that properly would be to intercept all calls to
  dlsym and redirect these functions by name to go to the real handle
  instead of ourselves - vastly overcomplicated for this edge case.
This commit is contained in:
baldurk
2018-01-11 12:09:29 +00:00
parent b5d9034698
commit da5cefbac2
2 changed files with 58 additions and 0 deletions
+57
View File
@@ -799,6 +799,63 @@ __attribute__((visibility("default"))) void glXDestroyWindow(Display *dpy, GLXWi
return glhooks.glXDestroyWindow_real(dpy, window);
}
// because we intercept all dlopen calls to "libGL.so*" to ourselves, we can interfere with some
// vulkan ICDs. For some reason they point the vulkan ICD to that file and so the vulkan loader
// tries to get the bootstrap entry points from us. I think this is a distribution thing and is not
// true in the official nvidia package, I'm not sure.
// Unfortunately there's no perfect way to fix this, since if we declare a function the ICD doesn't
// support we're screwed. We just have to hope the ICD exports all these functions that we can
// forward on to.
// declare minimal typedefs to get by
typedef void *VkInstance;
enum VkResult
{
VK_ERROR_INCOMPATIBLE_DRIVER = -9
};
struct VkNegotiateLayerInterface;
typedef void (*PFN_vkVoidFunction)(void);
typedef PFN_vkVoidFunction (*PFN_vkGetInstanceProcAddr)(VkInstance instance, const char *pName);
typedef PFN_vkVoidFunction (*PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char *pName);
typedef VkResult (*PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct);
__attribute__((visibility("default"))) PFN_vkVoidFunction vk_icdGetInstanceProcAddr(
VkInstance instance, const char *pName)
{
PFN_vkGetInstanceProcAddr real =
(PFN_vkGetInstanceProcAddr)dlsym(libGLdlsymHandle, "vk_icdGetInstanceProcAddr");
if(real)
return real(instance, pName);
return NULL;
}
__attribute__((visibility("default"))) PFN_vkVoidFunction vk_icdGetPhysicalDeviceProcAddr(
VkInstance instance, const char *pName)
{
PFN_GetPhysicalDeviceProcAddr real =
(PFN_GetPhysicalDeviceProcAddr)dlsym(libGLdlsymHandle, "vk_icdGetPhysicalDeviceProcAddr");
if(real)
return real(instance, pName);
return NULL;
}
__attribute__((visibility("default"))) VkResult vk_icdNegotiateLoaderLayerInterfaceVersion(
VkNegotiateLayerInterface *pVersionStruct)
{
PFN_vkNegotiateLoaderLayerInterfaceVersion real = (PFN_vkNegotiateLoaderLayerInterfaceVersion)dlsym(
libGLdlsymHandle, "vk_icdNegotiateLoaderLayerInterfaceVersion");
if(real)
return real(pVersionStruct);
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
}; // extern "C"
bool OpenGLHook::PopulateHooks()
+1
View File
@@ -4,6 +4,7 @@
_fini;
gl[A-Z]*;
egl[A-Z]*;
vk_icd*;
dlopen;
_exit;
RENDERDOC_*;