From 3b62ea71a1421b4f24ffb084d3bcfeb1289f56dd Mon Sep 17 00:00:00 2001 From: Matt Chudleigh Date: Thu, 18 Mar 2021 11:33:46 -0700 Subject: [PATCH 1/3] Fix loader crash on windows --- src/vulkan.nim | 4 ++-- tools/utils.nim | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vulkan.nim b/src/vulkan.nim index 7ea1c9f..2b948c8 100644 --- a/src/vulkan.nim +++ b/src/vulkan.nim @@ -21,13 +21,13 @@ when not defined(vkCustomLoader): if isNil(vkHandleDLL): quit("could not load: " & vkDLL) - let vkGetProcAddress = cast[proc(s: cstring): pointer {.stdcall.}](symAddr(vkHandleDLL, "vkGetInstanceProcAddr")) + let vkGetProcAddress = cast[proc(inst: pointer, s: cstring): pointer {.stdcall.}](symAddr(vkHandleDLL, "vkGetInstanceProcAddr")) if vkGetProcAddress == nil: quit("failed to load `vkGetInstanceProcAddr` from " & vkDLL) vkGetProc = proc(procName: cstring): pointer {.cdecl.} = when defined(windows): - result = vkGetProcAddress(procName) + result = vkGetProcAddress(nil, procName) if result != nil: return result = symAddr(vkHandleDLL, procName) diff --git a/tools/utils.nim b/tools/utils.nim index b85cc2d..97cfc3b 100644 --- a/tools/utils.nim +++ b/tools/utils.nim @@ -24,13 +24,13 @@ when not defined(vkCustomLoader): if isNil(vkHandleDLL): quit("could not load: " & vkDLL) - let vkGetProcAddress = cast[proc(s: cstring): pointer {.stdcall.}](symAddr(vkHandleDLL, "vkGetInstanceProcAddr")) + let vkGetProcAddress = cast[proc(inst: pointer, s: cstring): pointer {.stdcall.}](symAddr(vkHandleDLL, "vkGetInstanceProcAddr")) if vkGetProcAddress == nil: quit("failed to load `vkGetInstanceProcAddr` from " & vkDLL) vkGetProc = proc(procName: cstring): pointer {.cdecl.} = when defined(windows): - result = vkGetProcAddress(procName) + result = vkGetProcAddress(nil, procName) if result != nil: return result = symAddr(vkHandleDLL, procName) From e5b73b1f72c6c254340f353c03cfb4c7d1ddc8e9 Mon Sep 17 00:00:00 2001 From: Matt Chudleigh Date: Thu, 18 Mar 2021 13:26:54 -0700 Subject: [PATCH 2/3] Change Vulkan initiation to conform to spec When dynamically binding Vulkan vkGetInstanceProcAddr() requires an existing instance for all functions except those related to creating an instance (see the documentation for vkGetInstanceProcAddr() ). This method conforms to the spec, but changes the API for initialization (see the tests). --- src/vulkan.nim | 30 ++++++++++++++++++++---------- tests/triangle.nim | 4 +++- tools/generator.nim | 6 +++++- tools/utils.nim | 22 ++++++++++++++++++++-- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/vulkan.nim b/src/vulkan.nim index 2b948c8..920b5df 100644 --- a/src/vulkan.nim +++ b/src/vulkan.nim @@ -6,6 +6,7 @@ ## Any edits will be overwritten by the generator. var vkGetProc: proc(procName: cstring): pointer {.cdecl.} +var currInst: pointer = nil when not defined(vkCustomLoader): import dynlib @@ -27,7 +28,7 @@ when not defined(vkCustomLoader): vkGetProc = proc(procName: cstring): pointer {.cdecl.} = when defined(windows): - result = vkGetProcAddress(nil, procName) + result = vkGetProcAddress(currInst, procName) if result != nil: return result = symAddr(vkHandleDLL, procName) @@ -9815,7 +9816,6 @@ proc newVkPhysicalDevice4444FormatsFeaturesEXT*(sType: VkStructureType, pNext: p # Procs var - vkCreateInstance*: proc(pCreateInfo: ptr VkInstanceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pInstance: ptr VkInstance ): VkResult {.stdcall.} vkDestroyInstance*: proc(instance: VkInstance, pAllocator: ptr VkAllocationCallbacks ): void {.stdcall.} vkEnumeratePhysicalDevices*: proc(instance: VkInstance, pPhysicalDeviceCount: ptr uint32 , pPhysicalDevices: ptr VkPhysicalDevice ): VkResult {.stdcall.} vkGetDeviceProcAddr*: proc(device: VkDevice, pName: cstring ): PFN_vkVoidFunction {.stdcall.} @@ -9828,9 +9828,6 @@ var vkGetPhysicalDeviceImageFormatProperties*: proc(physicalDevice: VkPhysicalDevice, format: VkFormat, `type`: VkImageType, tiling: VkImageTiling, usage: VkImageUsageFlags, flags: VkImageCreateFlags, pImageFormatProperties: ptr VkImageFormatProperties ): VkResult {.stdcall.} vkCreateDevice*: proc(physicalDevice: VkPhysicalDevice, pCreateInfo: ptr VkDeviceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pDevice: ptr VkDevice ): VkResult {.stdcall.} vkDestroyDevice*: proc(device: VkDevice, pAllocator: ptr VkAllocationCallbacks ): void {.stdcall.} - vkEnumerateInstanceVersion*: proc(pApiVersion: ptr uint32 ): VkResult {.stdcall.} - vkEnumerateInstanceLayerProperties*: proc(pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.} - vkEnumerateInstanceExtensionProperties*: proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.} vkEnumerateDeviceLayerProperties*: proc(physicalDevice: VkPhysicalDevice, pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.} vkEnumerateDeviceExtensionProperties*: proc(physicalDevice: VkPhysicalDevice, pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.} vkGetDeviceQueue*: proc(device: VkDevice, queueFamilyIndex: uint32, queueIndex: uint32, pQueue: ptr VkQueue ): void {.stdcall.} @@ -10210,7 +10207,6 @@ var # Vulkan 1_0 proc vkLoad1_0*() = - vkCreateInstance = cast[proc(pCreateInfo: ptr VkInstanceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pInstance: ptr VkInstance ): VkResult {.stdcall.}](vkGetProc("vkCreateInstance")) vkDestroyInstance = cast[proc(instance: VkInstance, pAllocator: ptr VkAllocationCallbacks ): void {.stdcall.}](vkGetProc("vkDestroyInstance")) vkEnumeratePhysicalDevices = cast[proc(instance: VkInstance, pPhysicalDeviceCount: ptr uint32 , pPhysicalDevices: ptr VkPhysicalDevice ): VkResult {.stdcall.}](vkGetProc("vkEnumeratePhysicalDevices")) vkGetPhysicalDeviceFeatures = cast[proc(physicalDevice: VkPhysicalDevice, pFeatures: ptr VkPhysicalDeviceFeatures ): void {.stdcall.}](vkGetProc("vkGetPhysicalDeviceFeatures")) @@ -10223,9 +10219,7 @@ proc vkLoad1_0*() = vkGetDeviceProcAddr = cast[proc(device: VkDevice, pName: cstring ): PFN_vkVoidFunction {.stdcall.}](vkGetProc("vkGetDeviceProcAddr")) vkCreateDevice = cast[proc(physicalDevice: VkPhysicalDevice, pCreateInfo: ptr VkDeviceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pDevice: ptr VkDevice ): VkResult {.stdcall.}](vkGetProc("vkCreateDevice")) vkDestroyDevice = cast[proc(device: VkDevice, pAllocator: ptr VkAllocationCallbacks ): void {.stdcall.}](vkGetProc("vkDestroyDevice")) - vkEnumerateInstanceExtensionProperties = cast[proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceExtensionProperties")) vkEnumerateDeviceExtensionProperties = cast[proc(physicalDevice: VkPhysicalDevice, pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateDeviceExtensionProperties")) - vkEnumerateInstanceLayerProperties = cast[proc(pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceLayerProperties")) vkEnumerateDeviceLayerProperties = cast[proc(physicalDevice: VkPhysicalDevice, pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateDeviceLayerProperties")) vkGetDeviceQueue = cast[proc(device: VkDevice, queueFamilyIndex: uint32, queueIndex: uint32, pQueue: ptr VkQueue ): void {.stdcall.}](vkGetProc("vkGetDeviceQueue")) vkQueueSubmit = cast[proc(queue: VkQueue, submitCount: uint32, pSubmits: ptr VkSubmitInfo , fence: VkFence): VkResult {.stdcall.}](vkGetProc("vkQueueSubmit")) @@ -10350,7 +10344,6 @@ proc vkLoad1_0*() = # Vulkan 1_1 proc vkLoad1_1*() = - vkEnumerateInstanceVersion = cast[proc(pApiVersion: ptr uint32 ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceVersion")) vkBindBufferMemory2 = cast[proc(device: VkDevice, bindInfoCount: uint32, pBindInfos: ptr VkBindBufferMemoryInfo ): VkResult {.stdcall.}](vkGetProc("vkBindBufferMemory2")) vkBindImageMemory2 = cast[proc(device: VkDevice, bindInfoCount: uint32, pBindInfos: ptr VkBindImageMemoryInfo ): VkResult {.stdcall.}](vkGetProc("vkBindImageMemory2")) vkGetDeviceGroupPeerMemoryFeatures = cast[proc(device: VkDevice, heapIndex: uint32, localDeviceIndex: uint32, remoteDeviceIndex: uint32, pPeerMemoryFeatures: ptr VkPeerMemoryFeatureFlags ): void {.stdcall.}](vkGetProc("vkGetDeviceGroupPeerMemoryFeatures")) @@ -10835,7 +10828,24 @@ proc loadVK_EXT_directfb_surface*() = vkCreateDirectFBSurfaceEXT = cast[proc(instance: VkInstance, pCreateInfo: ptr VkDirectFBSurfaceCreateInfoEXT , pAllocator: ptr VkAllocationCallbacks , pSurface: ptr VkSurfaceKHR ): VkResult {.stdcall.}](vkGetProc("vkCreateDirectFBSurfaceEXT")) vkGetPhysicalDeviceDirectFBPresentationSupportEXT = cast[proc(physicalDevice: VkPhysicalDevice, queueFamilyIndex: uint32, dfb: ptr IDirectFB ): VkBool32 {.stdcall.}](vkGetProc("vkGetPhysicalDeviceDirectFBPresentationSupportEXT")) -proc vkInit*(load1_0: bool = true, load1_1: bool = true): bool = +var + vkCreateInstance*: proc(pCreateInfo: ptr VkInstanceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pInstance: ptr VkInstance ): VkResult {.stdcall.} + vkEnumerateInstanceExtensionProperties*: proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.} + vkEnumerateInstanceLayerProperties*: proc(pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.} + vkEnumerateInstanceVersion*: proc(pApiVersion: ptr uint32 ): VkResult {.stdcall.} + +proc vkPreload*(load1_1: bool = true) = + vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring ): PFN_vkVoidFunction {.stdcall.}](symAddr(vkHandleDLL, "vkGetInstanceProcAddr")) + + vkCreateInstance = cast[proc(pCreateInfo: ptr VkInstanceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pInstance: ptr VkInstance ): VkResult {.stdcall.}](vkGetProc("vkCreateInstance")) + vkEnumerateInstanceExtensionProperties = cast[proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceExtensionProperties")) + vkEnumerateInstanceLayerProperties = cast[proc(pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceLayerProperties")) + + if load1_1: + vkEnumerateInstanceVersion = cast[proc(pApiVersion: ptr uint32 ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceVersion")) + +proc vkInit*(instance: VkInstance, load1_0: bool = true, load1_1: bool = true): bool = + currInst = cast[pointer](instance) if load1_0: vkLoad1_0() when not defined(macosx): diff --git a/tests/triangle.nim b/tests/triangle.nim index 6c0d8eb..8e80e63 100644 --- a/tests/triangle.nim +++ b/tests/triangle.nim @@ -584,8 +584,10 @@ var semaphores: Semaphores proc init*(glfwExtensions: cstringArray, glfwExtensionCount: uint32, createSurface: CreateSurfaceProc) = - doAssert vkInit() + vkPreload(); instance = createInstance(glfwExtensions, glfwExtensionCount) + doAssert vkInit(instance) + surface = createSurface(instance) physicalDevice = pickPhysicalDevice(instance, surface) device = createLogicalDevice(physicalDevice, surface, graphicsQueue, presentQueue) diff --git a/tools/generator.nim b/tools/generator.nim index a71c00e..bd33003 100644 --- a/tools/generator.nim +++ b/tools/generator.nim @@ -364,7 +364,11 @@ proc genProcs(node: XmlNode, output: var string) = vkProc.rVal = vkProc.rVal[0 ..< vkProc.rVal.len - 1] vkProc.rVal = vkProc.rVal.translateType() - if vkProc.name == "vkGetTransformFeedbacki_v": + # Skip commands that are preloaded + if vkProc.name == "vkCreateInstance" or + vkProc.name == "vkEnumerateInstanceExtensionProperties" or + vkProc.name == "vkEnumerateInstanceLayerProperties" or + vkProc.name == "vkEnumerateInstanceVersion": continue for param in command.findAll("param"): diff --git a/tools/utils.nim b/tools/utils.nim index 97cfc3b..64789b0 100644 --- a/tools/utils.nim +++ b/tools/utils.nim @@ -9,6 +9,7 @@ const srcHeader* = """ ## Any edits will be overwritten by the generator. var vkGetProc: proc(procName: cstring): pointer {.cdecl.} +var currInst: pointer = nil when not defined(vkCustomLoader): import dynlib @@ -30,7 +31,7 @@ when not defined(vkCustomLoader): vkGetProc = proc(procName: cstring): pointer {.cdecl.} = when defined(windows): - result = vkGetProcAddress(nil, procName) + result = vkGetProcAddress(currInst, procName) if result != nil: return result = symAddr(vkHandleDLL, procName) @@ -49,7 +50,24 @@ type """ const vkInit* = """ -proc vkInit*(load1_0: bool = true, load1_1: bool = true): bool = +var + vkCreateInstance*: proc(pCreateInfo: ptr VkInstanceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pInstance: ptr VkInstance ): VkResult {.stdcall.} + vkEnumerateInstanceExtensionProperties*: proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.} + vkEnumerateInstanceLayerProperties*: proc(pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.} + vkEnumerateInstanceVersion*: proc(pApiVersion: ptr uint32 ): VkResult {.stdcall.} + +proc vkPreload*(load1_1: bool = true) = + vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring ): PFN_vkVoidFunction {.stdcall.}](symAddr(vkHandleDLL, "vkGetInstanceProcAddr")) + + vkCreateInstance = cast[proc(pCreateInfo: ptr VkInstanceCreateInfo , pAllocator: ptr VkAllocationCallbacks , pInstance: ptr VkInstance ): VkResult {.stdcall.}](vkGetProc("vkCreateInstance")) + vkEnumerateInstanceExtensionProperties = cast[proc(pLayerName: cstring , pPropertyCount: ptr uint32 , pProperties: ptr VkExtensionProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceExtensionProperties")) + vkEnumerateInstanceLayerProperties = cast[proc(pPropertyCount: ptr uint32 , pProperties: ptr VkLayerProperties ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceLayerProperties")) + + if load1_1: + vkEnumerateInstanceVersion = cast[proc(pApiVersion: ptr uint32 ): VkResult {.stdcall.}](vkGetProc("vkEnumerateInstanceVersion")) + +proc vkInit*(instance: VkInstance, load1_0: bool = true, load1_1: bool = true): bool = + currInst = cast[pointer](instance) if load1_0: vkLoad1_0() when not defined(macosx): From 25b6e72adabb5f27a83e63bbae6df8ecdddb53d5 Mon Sep 17 00:00:00 2001 From: Leonardo Mariscal Date: Fri, 2 Apr 2021 15:44:50 -0600 Subject: [PATCH 3/3] Increase package's version --- vulkan.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkan.nimble b/vulkan.nimble index 5dd13f8..aa5b648 100644 --- a/vulkan.nimble +++ b/vulkan.nimble @@ -1,6 +1,6 @@ # Package -version = "1.2.0" +version = "1.2.1" author = "Leonardo Mariscal" description = "Vulkan bindings for Nim" license = "MIT"