Fix linking issues with dynamic Vulkan functions.

- Ensure Vulkan public symbols are not stripped from the library when
  statically linked to an app that calls all Vulkan functions dynamically.
- Per Vulkan 1.2 spec, support calling vkGetInstanceProcAddr() with a
  null instance, when vkGetInstanceProcAddr itself is the function name.
- Replace uses of strcmp() with mvkStringsAreEqual() to protect against
  null pointers, and provide a direct bool output (unrelated cleanup).
This commit is contained in:
Bill Hollings 2023-01-10 07:22:05 -05:00
parent 7a320974d1
commit 682906976d
7 changed files with 26 additions and 14 deletions

View File

@ -102,8 +102,7 @@ extern "C" {
#endif
/** Directive to identify public symbols. */
#define MVK_PUBLIC_SYMBOL __attribute__((visibility("default")))
#define MVK_PUBLIC_SYMBOL __attribute__((visibility("default"))) __attribute__((used))
/** Directive to make a public alias of another symbol. */
#define MVK_PUBLIC_ALIAS(ALIAS, TARGET) asm(".globl _" #ALIAS "\n\t_" #ALIAS " = _" #TARGET)

View File

@ -22,6 +22,10 @@ Released TBD
`MTLCommandBuffer` is finished using it.
- Fix memory leak of `MVKFences` and `MVKSemaphores` when
a swapchain image is acquired more than it is presented.
- Ensure Vulkan public symbols are not stripped from the library when
statically linked to an app that calls all Vulkan functions dynamically.
- Per Vulkan 1.2 spec, support calling `vkGetInstanceProcAddr()` with a
null instance, when `vkGetInstanceProcAddr` itself is the function name.

View File

@ -449,7 +449,6 @@ void MVKInstance::initProcAddrs() {
ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceProperties);
ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceQueueFamilyProperties);
ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceMemoryProperties);
ADD_INST_ENTRY_POINT(vkGetInstanceProcAddr);
ADD_INST_ENTRY_POINT(vkCreateDevice);
ADD_INST_ENTRY_POINT(vkEnumerateDeviceExtensionProperties);
ADD_INST_ENTRY_POINT(vkEnumerateDeviceLayerProperties);

View File

@ -141,7 +141,7 @@ bool MVKExtensionList::isEnabled(const char* extnName) const {
const MVKExtension* extnAry = &extensionArray;
for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
const MVKExtension& extn = extnAry[extnIdx];
if ( strcmp(extn.pProperties->extensionName, extnName) == 0 ) {
if (mvkStringsAreEqual(extn.pProperties->extensionName, extnName)) {
return extn.enabled;
}
}
@ -153,7 +153,7 @@ void MVKExtensionList::enable(const char* extnName) {
MVKExtension* extnAry = &extensionArray;
for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
MVKExtension& extn = extnAry[extnIdx];
if ( strcmp(extn.pProperties->extensionName, extnName) == 0 ) {
if (mvkStringsAreEqual(extn.pProperties->extensionName, extnName)) {
extn.enabled = true;
return;
}

View File

@ -65,7 +65,7 @@ MVKLayer* MVKLayerManager::getLayerNamed(const char* pLayerName) {
uint32_t layCnt = (uint32_t)_layers.size();
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
MVKLayer* pLayer = &_layers[layIdx];
if ( strcmp(pLayer->getName(), pLayerName) == 0 ) { return pLayer; }
if (mvkStringsAreEqual(pLayer->getName(), pLayerName)) { return pLayer; }
}
return VK_NULL_HANDLE;
}

View File

@ -549,6 +549,15 @@ bool mvkAreEqual(const T* pV1, const T* pV2, size_t count = 1) {
return (pV1 && pV2) ? (memcmp(pV1, pV2, sizeof(T) * count) == 0) : false;
}
/**
* If both pV1 and pV2 are not null, returns whether the contents of the two strings are equal,
* otherwise returns false. This functionality is different than the char version of mvkAreEqual(),
* which works on individual chars or char arrays, not strings.
*/
static inline bool mvkStringsAreEqual(const char* pV1, const char* pV2, size_t count = 1) {
return (pV1 && pV2) ? (strcmp(pV1, pV2) == 0) : false;
}
/**
* Sets the value referenced by the destination pointer with the value referenced by
* the source pointer, and returns whether the value was set.

View File

@ -284,17 +284,18 @@ MVK_PUBLIC_VULKAN_SYMBOL PFN_vkVoidFunction vkGetInstanceProcAddr(
VkInstance instance,
const char* pName) {
MVKTraceVulkanCallStart();
// Handle the special platform functions where the instance parameter may be NULL.
PFN_vkVoidFunction func = nullptr;
if (strcmp(pName, "vkCreateInstance") == 0) {
MVKTraceVulkanCallStart();
if (mvkStringsAreEqual(pName, "vkGetInstanceProcAddr")) {
func = (PFN_vkVoidFunction)vkGetInstanceProcAddr;
} else if (mvkStringsAreEqual(pName, "vkCreateInstance")) {
func = (PFN_vkVoidFunction)vkCreateInstance;
} else if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) {
} else if (mvkStringsAreEqual(pName, "vkEnumerateInstanceExtensionProperties")) {
func = (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties;
} else if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) {
} else if (mvkStringsAreEqual(pName, "vkEnumerateInstanceLayerProperties")) {
func = (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties;
} else if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) {
} else if (mvkStringsAreEqual(pName, "vkEnumerateInstanceVersion")) {
func = (PFN_vkVoidFunction)vkEnumerateInstanceVersion;
} else if (instance) {
MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
@ -3419,9 +3420,9 @@ MVK_PUBLIC_SYMBOL PFN_vkVoidFunction vk_icdGetInstanceProcAddr(
MVKTraceVulkanCallStart();
PFN_vkVoidFunction func = nullptr;
if (strcmp(pName, "vk_icdNegotiateLoaderICDInterfaceVersion") == 0) {
if (mvkStringsAreEqual(pName, "vk_icdNegotiateLoaderICDInterfaceVersion")) {
func = (PFN_vkVoidFunction)vk_icdNegotiateLoaderICDInterfaceVersion;
} else if (strcmp(pName, "vk_icdGetPhysicalDeviceProcAddr") == 0) {
} else if (mvkStringsAreEqual(pName, "vk_icdGetPhysicalDeviceProcAddr")) {
func = (PFN_vkVoidFunction)vk_icdGetPhysicalDeviceProcAddr;
} else {
func = vkGetInstanceProcAddr(instance, pName);