An aside to the other comments, but I feel like you're probably approaching this the wrong way. You probably shouldn't be trying to wrap the Vulkan structures; instead, you should be trying to wrap the function calls and provide custom struct/class types. In Vulkan written in C, the pattern is to declare a struct on the stack and then pass it to a Vulkan function, like this:
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, ... };
submitInfo.pWaitSemaphores = &waitSemaphores;
vkQueueSubmit(queue, 1, &submitInfo, fence)
However, if you do that in Swift, you end up with a 'pyramid of doom'; every time you'd take the address of a stack variable in C with & you need a withUnsafePointer(to:) call in Swift. How I'd approach this would be to instead declare a VulkanSubmitInfo struct as you would in Swift:
struct VulkanSubmitInfo {
var waitSemaphores : [VulkanSemaphore]
var waitDestinationStageMasks : [VkPipelineStateFlags]
var commandBuffers : [VulkanCommandBuffer]
var signalSemaphores : [VulkanSemaphore]
}
and then have a function that provides a closure with a VkSubmitInfo. This function would be the only place that contains the 'pyramid of doom' per type:
extension VulkanSubmitInfo {
func withSubmitInfo(_ perform: (inout VkSubmitInfo) -> Void) {
var submitInfo = VkSubmitInfo()
... // structure type, pNext
// Map to the underlying VkSemaphore? for each VulkanSemaphore.
var vkSemaphores = self.semaphores.map { $0.vkSemaphore as VkSemaphore? }
vkSemaphores.withUnsafeBufferPointer { waitSemaphores in
submitInfo.pWaitSemaphores = waitSemaphores.baseAddress
submitInfo.waitSemaphoreCount = UInt32(waitSemaphores.count)
// nest more for commandBuffers, signal semaphores etc.
perform(&submitInfo)
}
}
}
Then, you can declare something like:
class VulkanQueue {
var queue : VkQueue
// You can write a simple method that submits only one VulkanSubmitInfo
func submit(_ submitInfo: VulkanSubmitInfo, fence: VkFence) {
submitInfo.withSubmitInfo { vkQueueSubmit(queue, 1, $0, fence) }
}
// You can also write a function that deals with arrays recursively
// by using an inner helper function to traverse the list.
// If you've ever used Haskell or similar languages this pattern
// should be familiar.
// Note that this nested style means we never exit the `withSubmitInfo` closures,
// which means that they are guaranteed to stay valid.
func submit(_ submitInfos: [VulkanSubmitInfo], fence: VkFence) {
var vkSubmitInfos = [VkSubmitInfo]()
func withSubmitInfos(_ s: ArraySlice<VulkanSubmitInfo>) {
if let first = s.first {
first.withSubmitInfo {
vkSubmitInfos.append($0)
withSubmitInfos(s.dropFirst())
}
} else {
vkQueueSubmit(self.queue, vkSubmitInfos.count, &vkSubmitInfos, fence)
}
}
withSubmitInfos(submitInfos[submitInfos.indices])
}
}
I will add that it gets pretty tricky to make an idiomatic Vulkan wrapper API in Swift; you need to think in terms of variable lifetimes, nested closures, and recursive function calls to manage those closures.