How to property cast a C type to another C function type in Swift

Ok, so hi everyone! I have another weird issue with Vulkan and Swift. So the quick rundown is I have made the very different decision to write an Open Source game & engine in Swift using the Vulkan API. Vulkan is a C API and I absolutely love swift's way of handling the interpolation between the two. As of today, I ran into an issue with trying to get the proc address to one of the functions from the C API. The code for the project, including the bug discussed here is on GITHUB
So basically, the issue all arises from this C API call from the vulkan 1.1.130 spec:

PFN_vkVoidFunction vkGetInstanceProcAddr(
    VkInstance                                  instance,
    const char*                                 pName);

As you can see, this function returns a pointer C function which is normally ok, but the specification states this:
vkGetInstanceProcAddr itself is obtained in a platform- and loader- specific manner. Typically, the loader library will export this command as a function symbol, so applications can link against the loader library, or load it dynamically and look up the symbol using platform-specific APIs.

The table below defines the various use cases for vkGetInstanceProcAddr and expected return value (“fp” is “function pointer”) for each case.

The returned function pointer is of type PFN_vkVoidFunction, and must be cast to the type of the command being queried.

So the spec states that you must cast the type PFN_vkVoidFunction to the type of the command that you are fetching for.

Swift imports the PFN_vkVoidFunction type as () -> Void

I need to cast this type to the type of the function that will be returned, which is a PFN_vkCreateAccelerationStructureNV (which is imported as (VkDevice?, UnsafePointer<VkAccelerationStructureCreateInfoNV>?, UnsafePointer<VkAllocationCallbacks>?, UnsafeMutablePointer<VkAccelerationStructureNV?>?) -> VkResult in swift). The problem is I don't know any way I can go about casting this type in Swift to the needed function type.
I tried this snippet of code in a function of a class:

let vkCreateAccelerationStructureNV = self.device.instance.getProcAddr(name: "vkCreateAccelerationStructureNV") as! PFN_vkCreateAccelerationStructureNV
vkCreateAccelerationStructureNV(self.device.handle, &createInfo, nil, &self.handle)

which errors out when run: Could not cast value of type '@convention(c) () -> ()' (0x7faaaf9dbe60) to '@convention(c) (Swift.Optional<Swift.OpaquePointer>, Swift.Optional<Swift.UnsafePointer<__C.VkAccelerationStructureCreateInfoNV>>, Swift.Optional<Swift.UnsafePointer<__C.VkAllocationCallbacks>>, Swift.Optional<Swift.UnsafeMutablePointer<Swift.Optional<Swift.OpaquePointer>>>) -> __C.VkResult' (0x7faaaf9dc258). The page of the vulkan spec that states this can be found HERE.

So basically my quesion is, how would I go about getting that function returned converted or casted into the function that I need it to be. In C++, the solution would be something like this:

PFN_vkGetPhysicalDeviceFeatures2KHR pvkGetPhysicalDeviceFeatures2KHR  = vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR");
// use pvkGetPhysicalDeviceFeatures2KHR

But in swift I cannot cast the value from the returned PFN_vkVoidFunction to the PFN_vkCreateAccelerationStructureNV. I know this is a long post super sorry about the rambling I just have no idea how to go about fixing this issue in Swift. Any ideas on how I can get that type to cast properly? Again thank you all so much for the help!

Have you tried unsafeBitCast(_:to:)?

1 Like

When I try to unsafe bit cast between the two types, I get this error: Fatal error: Can't unsafeBitCast between types of different sizes: file /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-18_04/swift/stdlib/public/core/Builtin.swift, line 83

Oop wait I think I just fixed that issue by making the return type of the function a PFN_vkVoidFunction and then casting it. This may work just gotta test it a bit more! THANK YOU SO MUCH