changeset 92:e872cf354110

add: more stuff for the vulkan API wrappers
author Sam <sam@basx.dev>
date Tue, 28 Feb 2023 00:08:28 +0700
parents 2e9823f9193f
children cb773e81032f
files src/semicongine/engine.nim src/semicongine/vulkan.nim src/semicongine/vulkan/api.nim src/semicongine/vulkan/buffer.nim src/semicongine/vulkan/buffers.nim src/semicongine/vulkan/device.nim src/semicongine/vulkan/instance.nim src/semicongine/vulkan/utils.nim src/semicongine/vulkan_helpers.nim src/vulkan_api/vulkan_api_generator.nim
diffstat 10 files changed, 454 insertions(+), 125 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/engine.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/engine.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -111,7 +111,7 @@
 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[
     PhysicalDevice] =
   for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance):
-    var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice))
+    var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: vulkan.getDeviceExtensions(vulkanPhysicalDevice))
     vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties))
     vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features))
     device.formats = vulkanPhysicalDevice.getDeviceSurfaceFormats(surface)
@@ -886,20 +886,17 @@
       engine.vulkan.framebuffers)
 
   for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
-    engine.vulkan.device.device.vkDestroySemaphore(
-        engine.vulkan.imageAvailableSemaphores[i], nil)
-    engine.vulkan.device.device.vkDestroySemaphore(
-        engine.vulkan.renderFinishedSemaphores[i], nil)
+    engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil)
+    engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil)
     engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil)
 
   engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil)
-  engine.vulkan.device.device.vkDestroyCommandPool(
-      engine.vulkan.device.commandPool, nil)
+  engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.device.commandPool, nil)
 
   engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil)
   engine.vulkan.device.device.vkDestroyDevice(nil)
   when DEBUG_LOG:
     engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil)
   engine.window.trash()
-  engine.vulkan.instance.vkDestroyInstance(
-      nil) # needs to happen after window is trashed as the driver might have a hook registered for the window destruction
+  # needs to happen after window is trashed as the driver might have a hook registered for the window destruction
+  engine.vulkan.instance.vkDestroyInstance(nil)
--- a/src/semicongine/vulkan.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/vulkan.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -1,2 +1,14 @@
 import ./vulkan/api
 export api
+
+import ./vulkan/instance
+export instance
+
+import ./vulkan/device
+export device
+
+import ./vulkan/buffer
+export buffer
+
+import ./vulkan/memory
+export memory
--- a/src/semicongine/vulkan/api.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/vulkan/api.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -2,6 +2,7 @@
 import std/tables
 import std/strutils
 import std/logging
+import std/typetraits
 import std/macros
 import std/private/digitsutils
 from typetraits import HoleyEnum
@@ -135,6 +136,150 @@
   VkVideoSessionParametersKHR* = distinct VkNonDispatchableHandle
   VkSemaphoreSciSyncPoolNV* = distinct VkNonDispatchableHandle
   VkRemoteAddressNV* = pointer
+proc `$`*(handle: VkInstance): string = "VkInstance(" & $(uint(handle)) & ")"
+proc valid*(handle: VkInstance): bool = uint(handle) != 0
+proc reset*(handle: var VkInstance) = handle = VkInstance(0)
+proc `$`*(handle: VkPhysicalDevice): string = "VkPhysicalDevice(" & $(uint(handle)) & ")"
+proc valid*(handle: VkPhysicalDevice): bool = uint(handle) != 0
+proc reset*(handle: var VkPhysicalDevice) = handle = VkPhysicalDevice(0)
+proc `$`*(handle: VkDevice): string = "VkDevice(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDevice): bool = uint(handle) != 0
+proc reset*(handle: var VkDevice) = handle = VkDevice(0)
+proc `$`*(handle: VkQueue): string = "VkQueue(" & $(uint(handle)) & ")"
+proc valid*(handle: VkQueue): bool = uint(handle) != 0
+proc reset*(handle: var VkQueue) = handle = VkQueue(0)
+proc `$`*(handle: VkCommandBuffer): string = "VkCommandBuffer(" & $(uint(handle)) & ")"
+proc valid*(handle: VkCommandBuffer): bool = uint(handle) != 0
+proc reset*(handle: var VkCommandBuffer) = handle = VkCommandBuffer(0)
+proc `$`*(handle: VkDeviceMemory): string = "VkDeviceMemory(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDeviceMemory): bool = uint(handle) != 0
+proc reset*(handle: var VkDeviceMemory) = handle = VkDeviceMemory(0)
+proc `$`*(handle: VkCommandPool): string = "VkCommandPool(" & $(uint(handle)) & ")"
+proc valid*(handle: VkCommandPool): bool = uint(handle) != 0
+proc reset*(handle: var VkCommandPool) = handle = VkCommandPool(0)
+proc `$`*(handle: VkBuffer): string = "VkBuffer(" & $(uint(handle)) & ")"
+proc valid*(handle: VkBuffer): bool = uint(handle) != 0
+proc reset*(handle: var VkBuffer) = handle = VkBuffer(0)
+proc `$`*(handle: VkBufferView): string = "VkBufferView(" & $(uint(handle)) & ")"
+proc valid*(handle: VkBufferView): bool = uint(handle) != 0
+proc reset*(handle: var VkBufferView) = handle = VkBufferView(0)
+proc `$`*(handle: VkImage): string = "VkImage(" & $(uint(handle)) & ")"
+proc valid*(handle: VkImage): bool = uint(handle) != 0
+proc reset*(handle: var VkImage) = handle = VkImage(0)
+proc `$`*(handle: VkImageView): string = "VkImageView(" & $(uint(handle)) & ")"
+proc valid*(handle: VkImageView): bool = uint(handle) != 0
+proc reset*(handle: var VkImageView) = handle = VkImageView(0)
+proc `$`*(handle: VkShaderModule): string = "VkShaderModule(" & $(uint(handle)) & ")"
+proc valid*(handle: VkShaderModule): bool = uint(handle) != 0
+proc reset*(handle: var VkShaderModule) = handle = VkShaderModule(0)
+proc `$`*(handle: VkPipeline): string = "VkPipeline(" & $(uint(handle)) & ")"
+proc valid*(handle: VkPipeline): bool = uint(handle) != 0
+proc reset*(handle: var VkPipeline) = handle = VkPipeline(0)
+proc `$`*(handle: VkPipelineLayout): string = "VkPipelineLayout(" & $(uint(handle)) & ")"
+proc valid*(handle: VkPipelineLayout): bool = uint(handle) != 0
+proc reset*(handle: var VkPipelineLayout) = handle = VkPipelineLayout(0)
+proc `$`*(handle: VkSampler): string = "VkSampler(" & $(uint(handle)) & ")"
+proc valid*(handle: VkSampler): bool = uint(handle) != 0
+proc reset*(handle: var VkSampler) = handle = VkSampler(0)
+proc `$`*(handle: VkDescriptorSet): string = "VkDescriptorSet(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDescriptorSet): bool = uint(handle) != 0
+proc reset*(handle: var VkDescriptorSet) = handle = VkDescriptorSet(0)
+proc `$`*(handle: VkDescriptorSetLayout): string = "VkDescriptorSetLayout(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDescriptorSetLayout): bool = uint(handle) != 0
+proc reset*(handle: var VkDescriptorSetLayout) = handle = VkDescriptorSetLayout(0)
+proc `$`*(handle: VkDescriptorPool): string = "VkDescriptorPool(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDescriptorPool): bool = uint(handle) != 0
+proc reset*(handle: var VkDescriptorPool) = handle = VkDescriptorPool(0)
+proc `$`*(handle: VkFence): string = "VkFence(" & $(uint(handle)) & ")"
+proc valid*(handle: VkFence): bool = uint(handle) != 0
+proc reset*(handle: var VkFence) = handle = VkFence(0)
+proc `$`*(handle: VkSemaphore): string = "VkSemaphore(" & $(uint(handle)) & ")"
+proc valid*(handle: VkSemaphore): bool = uint(handle) != 0
+proc reset*(handle: var VkSemaphore) = handle = VkSemaphore(0)
+proc `$`*(handle: VkEvent): string = "VkEvent(" & $(uint(handle)) & ")"
+proc valid*(handle: VkEvent): bool = uint(handle) != 0
+proc reset*(handle: var VkEvent) = handle = VkEvent(0)
+proc `$`*(handle: VkQueryPool): string = "VkQueryPool(" & $(uint(handle)) & ")"
+proc valid*(handle: VkQueryPool): bool = uint(handle) != 0
+proc reset*(handle: var VkQueryPool) = handle = VkQueryPool(0)
+proc `$`*(handle: VkFramebuffer): string = "VkFramebuffer(" & $(uint(handle)) & ")"
+proc valid*(handle: VkFramebuffer): bool = uint(handle) != 0
+proc reset*(handle: var VkFramebuffer) = handle = VkFramebuffer(0)
+proc `$`*(handle: VkRenderPass): string = "VkRenderPass(" & $(uint(handle)) & ")"
+proc valid*(handle: VkRenderPass): bool = uint(handle) != 0
+proc reset*(handle: var VkRenderPass) = handle = VkRenderPass(0)
+proc `$`*(handle: VkPipelineCache): string = "VkPipelineCache(" & $(uint(handle)) & ")"
+proc valid*(handle: VkPipelineCache): bool = uint(handle) != 0
+proc reset*(handle: var VkPipelineCache) = handle = VkPipelineCache(0)
+proc `$`*(handle: VkIndirectCommandsLayoutNV): string = "VkIndirectCommandsLayoutNV(" & $(uint(handle)) & ")"
+proc valid*(handle: VkIndirectCommandsLayoutNV): bool = uint(handle) != 0
+proc reset*(handle: var VkIndirectCommandsLayoutNV) = handle = VkIndirectCommandsLayoutNV(0)
+proc `$`*(handle: VkDescriptorUpdateTemplate): string = "VkDescriptorUpdateTemplate(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDescriptorUpdateTemplate): bool = uint(handle) != 0
+proc reset*(handle: var VkDescriptorUpdateTemplate) = handle = VkDescriptorUpdateTemplate(0)
+proc `$`*(handle: VkSamplerYcbcrConversion): string = "VkSamplerYcbcrConversion(" & $(uint(handle)) & ")"
+proc valid*(handle: VkSamplerYcbcrConversion): bool = uint(handle) != 0
+proc reset*(handle: var VkSamplerYcbcrConversion) = handle = VkSamplerYcbcrConversion(0)
+proc `$`*(handle: VkValidationCacheEXT): string = "VkValidationCacheEXT(" & $(uint(handle)) & ")"
+proc valid*(handle: VkValidationCacheEXT): bool = uint(handle) != 0
+proc reset*(handle: var VkValidationCacheEXT) = handle = VkValidationCacheEXT(0)
+proc `$`*(handle: VkAccelerationStructureKHR): string = "VkAccelerationStructureKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkAccelerationStructureKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkAccelerationStructureKHR) = handle = VkAccelerationStructureKHR(0)
+proc `$`*(handle: VkAccelerationStructureNV): string = "VkAccelerationStructureNV(" & $(uint(handle)) & ")"
+proc valid*(handle: VkAccelerationStructureNV): bool = uint(handle) != 0
+proc reset*(handle: var VkAccelerationStructureNV) = handle = VkAccelerationStructureNV(0)
+proc `$`*(handle: VkPerformanceConfigurationINTEL): string = "VkPerformanceConfigurationINTEL(" & $(uint(handle)) & ")"
+proc valid*(handle: VkPerformanceConfigurationINTEL): bool = uint(handle) != 0
+proc reset*(handle: var VkPerformanceConfigurationINTEL) = handle = VkPerformanceConfigurationINTEL(0)
+proc `$`*(handle: VkBufferCollectionFUCHSIA): string = "VkBufferCollectionFUCHSIA(" & $(uint(handle)) & ")"
+proc valid*(handle: VkBufferCollectionFUCHSIA): bool = uint(handle) != 0
+proc reset*(handle: var VkBufferCollectionFUCHSIA) = handle = VkBufferCollectionFUCHSIA(0)
+proc `$`*(handle: VkDeferredOperationKHR): string = "VkDeferredOperationKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDeferredOperationKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkDeferredOperationKHR) = handle = VkDeferredOperationKHR(0)
+proc `$`*(handle: VkPrivateDataSlot): string = "VkPrivateDataSlot(" & $(uint(handle)) & ")"
+proc valid*(handle: VkPrivateDataSlot): bool = uint(handle) != 0
+proc reset*(handle: var VkPrivateDataSlot) = handle = VkPrivateDataSlot(0)
+proc `$`*(handle: VkCuModuleNVX): string = "VkCuModuleNVX(" & $(uint(handle)) & ")"
+proc valid*(handle: VkCuModuleNVX): bool = uint(handle) != 0
+proc reset*(handle: var VkCuModuleNVX) = handle = VkCuModuleNVX(0)
+proc `$`*(handle: VkCuFunctionNVX): string = "VkCuFunctionNVX(" & $(uint(handle)) & ")"
+proc valid*(handle: VkCuFunctionNVX): bool = uint(handle) != 0
+proc reset*(handle: var VkCuFunctionNVX) = handle = VkCuFunctionNVX(0)
+proc `$`*(handle: VkOpticalFlowSessionNV): string = "VkOpticalFlowSessionNV(" & $(uint(handle)) & ")"
+proc valid*(handle: VkOpticalFlowSessionNV): bool = uint(handle) != 0
+proc reset*(handle: var VkOpticalFlowSessionNV) = handle = VkOpticalFlowSessionNV(0)
+proc `$`*(handle: VkMicromapEXT): string = "VkMicromapEXT(" & $(uint(handle)) & ")"
+proc valid*(handle: VkMicromapEXT): bool = uint(handle) != 0
+proc reset*(handle: var VkMicromapEXT) = handle = VkMicromapEXT(0)
+proc `$`*(handle: VkDisplayKHR): string = "VkDisplayKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDisplayKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkDisplayKHR) = handle = VkDisplayKHR(0)
+proc `$`*(handle: VkDisplayModeKHR): string = "VkDisplayModeKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDisplayModeKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkDisplayModeKHR) = handle = VkDisplayModeKHR(0)
+proc `$`*(handle: VkSurfaceKHR): string = "VkSurfaceKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkSurfaceKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkSurfaceKHR) = handle = VkSurfaceKHR(0)
+proc `$`*(handle: VkSwapchainKHR): string = "VkSwapchainKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkSwapchainKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkSwapchainKHR) = handle = VkSwapchainKHR(0)
+proc `$`*(handle: VkDebugReportCallbackEXT): string = "VkDebugReportCallbackEXT(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDebugReportCallbackEXT): bool = uint(handle) != 0
+proc reset*(handle: var VkDebugReportCallbackEXT) = handle = VkDebugReportCallbackEXT(0)
+proc `$`*(handle: VkDebugUtilsMessengerEXT): string = "VkDebugUtilsMessengerEXT(" & $(uint(handle)) & ")"
+proc valid*(handle: VkDebugUtilsMessengerEXT): bool = uint(handle) != 0
+proc reset*(handle: var VkDebugUtilsMessengerEXT) = handle = VkDebugUtilsMessengerEXT(0)
+proc `$`*(handle: VkVideoSessionKHR): string = "VkVideoSessionKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkVideoSessionKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkVideoSessionKHR) = handle = VkVideoSessionKHR(0)
+proc `$`*(handle: VkVideoSessionParametersKHR): string = "VkVideoSessionParametersKHR(" & $(uint(handle)) & ")"
+proc valid*(handle: VkVideoSessionParametersKHR): bool = uint(handle) != 0
+proc reset*(handle: var VkVideoSessionParametersKHR) = handle = VkVideoSessionParametersKHR(0)
+proc `$`*(handle: VkSemaphoreSciSyncPoolNV): string = "VkSemaphoreSciSyncPoolNV(" & $(uint(handle)) & ")"
+proc valid*(handle: VkSemaphoreSciSyncPoolNV): bool = uint(handle) != 0
+proc reset*(handle: var VkSemaphoreSciSyncPoolNV) = handle = VkSemaphoreSciSyncPoolNV(0)
 type
   VkFramebufferCreateFlags* = distinct VkFlags
   VkQueryPoolCreateFlags* = distinct VkFlags
@@ -3314,13 +3459,13 @@
     VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2
   VkMemoryDecompressionMethodFlagBitsNV* {.size: 8.} = enum
     VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV = 0b0000000000000000000000000000000000000000000000000000000000000001
-converter BitsetToNumber*(flags: openArray[VkMemoryDecompressionMethodFlagBitsNV]): VkMemoryDecompressionMethodFlagsNV =
-    for flag in flags:
-      result = VkMemoryDecompressionMethodFlagsNV(int64(result) or int64(flag))
-converter NumberToBitset*(number: VkMemoryDecompressionMethodFlagsNV): seq[VkMemoryDecompressionMethodFlagBitsNV] =
-        for value in VkMemoryDecompressionMethodFlagBitsNV.items:
-          if (value.ord and int64(number)) > 0:
-            result.add value
+func toBits*(flags: openArray[VkMemoryDecompressionMethodFlagBitsNV]): VkMemoryDecompressionMethodFlagsNV =
+    for flag in flags:
+      result = VkMemoryDecompressionMethodFlagsNV(uint64(result) or uint64(flag))
+func toEnums*(number: VkMemoryDecompressionMethodFlagsNV): seq[VkMemoryDecompressionMethodFlagBitsNV] =
+    for value in VkMemoryDecompressionMethodFlagBitsNV.items:
+      if (cast[uint64](value) and uint64(number)) > 0:
+        result.add value
 type
   VkPerformanceCounterUnitKHR* {.size: sizeof(cint).} = enum
     VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0
@@ -3496,13 +3641,13 @@
     VK_ACCESS_2_MICROMAP_READ_BIT_EXT = 0b0000000000000000000100000000000000000000000000000000000000000000
     VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT = 0b0000000000000000001000000000000000000000000000000000000000000000
     VK_ACCESS_2_RESERVED_46_BIT_EXT = 0b0000000000000000010000000000000000000000000000000000000000000000
-converter BitsetToNumber*(flags: openArray[VkAccessFlagBits2]): VkAccessFlags2 =
-    for flag in flags:
-      result = VkAccessFlags2(int64(result) or int64(flag))
-converter NumberToBitset*(number: VkAccessFlags2): seq[VkAccessFlagBits2] =
-        for value in VkAccessFlagBits2.items:
-          if (value.ord and int64(number)) > 0:
-            result.add value
+func toBits*(flags: openArray[VkAccessFlagBits2]): VkAccessFlags2 =
+    for flag in flags:
+      result = VkAccessFlags2(uint64(result) or uint64(flag))
+func toEnums*(number: VkAccessFlags2): seq[VkAccessFlagBits2] =
+    for value in VkAccessFlagBits2.items:
+      if (cast[uint64](value) and uint64(number)) > 0:
+        result.add value
 const
   VK_ACCESS_2_NONE* = 0
 type
@@ -3548,13 +3693,13 @@
     VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0b0000000000000000000000001000000000000000000000000000000000000000
     VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0b0000000000000000000000010000000000000000000000000000000000000000
     VK_PIPELINE_STAGE_2_CLUSTER_CULLING_SHADER_BIT_HUAWEI = 0b0000000000000000000000100000000000000000000000000000000000000000
-converter BitsetToNumber*(flags: openArray[VkPipelineStageFlagBits2]): VkPipelineStageFlags2 =
-    for flag in flags:
-      result = VkPipelineStageFlags2(int64(result) or int64(flag))
-converter NumberToBitset*(number: VkPipelineStageFlags2): seq[VkPipelineStageFlagBits2] =
-        for value in VkPipelineStageFlagBits2.items:
-          if (value.ord and int64(number)) > 0:
-            result.add value
+func toBits*(flags: openArray[VkPipelineStageFlagBits2]): VkPipelineStageFlags2 =
+    for flag in flags:
+      result = VkPipelineStageFlags2(uint64(result) or uint64(flag))
+func toEnums*(number: VkPipelineStageFlags2): seq[VkPipelineStageFlagBits2] =
+    for value in VkPipelineStageFlagBits2.items:
+      if (cast[uint64](value) and uint64(number)) > 0:
+        result.add value
 const
   VK_PIPELINE_STAGE_2_NONE* = 0
 type
@@ -3974,13 +4119,13 @@
     VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 0b0000000000000000000001000000000000000000000000000000000000000000
     VK_FORMAT_FEATURE_2_RESERVED_44_BIT_EXT = 0b0000000000000000000100000000000000000000000000000000000000000000
     VK_FORMAT_FEATURE_2_RESERVED_45_BIT_EXT = 0b0000000000000000001000000000000000000000000000000000000000000000
-converter BitsetToNumber*(flags: openArray[VkFormatFeatureFlagBits2]): VkFormatFeatureFlags2 =
-    for flag in flags:
-      result = VkFormatFeatureFlags2(int64(result) or int64(flag))
-converter NumberToBitset*(number: VkFormatFeatureFlags2): seq[VkFormatFeatureFlagBits2] =
-        for value in VkFormatFeatureFlagBits2.items:
-          if (value.ord and int64(number)) > 0:
-            result.add value
+func toBits*(flags: openArray[VkFormatFeatureFlagBits2]): VkFormatFeatureFlags2 =
+    for flag in flags:
+      result = VkFormatFeatureFlags2(uint64(result) or uint64(flag))
+func toEnums*(number: VkFormatFeatureFlags2): seq[VkFormatFeatureFlagBits2] =
+    for value in VkFormatFeatureFlagBits2.items:
+      if (cast[uint64](value) and uint64(number)) > 0:
+        result.add value
 type
   VkRenderingFlagBits* {.size: sizeof(cint).} = enum
     VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0b00000000000000000000000000000001
@@ -4286,6 +4431,130 @@
     VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = 6
   VkDeviceFaultVendorBinaryHeaderVersionEXT* {.size: sizeof(cint).} = enum
     VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT_ENUM = 1
+proc `$`*(bitset: VkFramebufferCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkRenderPassCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSamplerCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineCacheCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineShaderStageCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDescriptorSetLayoutCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkInstanceCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDeviceQueueCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkBufferCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkBufferUsageFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkColorComponentFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkCommandPoolCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkCommandPoolResetFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkCommandBufferResetFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkCommandBufferUsageFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkCullModeFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkFenceCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkFormatFeatureFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageAspectFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageUsageFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageViewCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkMemoryHeapFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkAccessFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkMemoryPropertyFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkQueryControlFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkQueryPipelineStatisticFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkQueryResultFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkQueueFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkShaderStageFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSparseMemoryBindFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkStencilFaceFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineStageFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSparseImageFormatFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSampleCountFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkAttachmentDescriptionFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDescriptorPoolCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDependencyFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkEventCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineLayoutCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkIndirectCommandsLayoutUsageFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkIndirectStateFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkPrivateDataSlotCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSubpassDescriptionFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkResolveModeFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDescriptorBindingFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkConditionalRenderingFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkGeometryFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkGeometryInstanceFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkBuildAccelerationStructureFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkAccelerationStructureCreateFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkDeviceDiagnosticsConfigFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineCreationFeedbackFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPerformanceCounterDescriptionFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkSemaphoreWaitFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkToolPurposeFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkAccessFlags2): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineStageFlags2): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageConstraintsInfoFlagsFUCHSIA): string = $toEnums(bitset)
+proc `$`*(bitset: VkFormatFeatureFlags2): string = $toEnums(bitset)
+proc `$`*(bitset: VkRenderingFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineDepthStencilStateCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkPipelineColorBlendStateCreateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageCompressionFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkImageCompressionFixedRateFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkExportMetalObjectTypeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkDeviceAddressBindingFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkBuildMicromapFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkMicromapCreateFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkMemoryDecompressionMethodFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkCompositeAlphaFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkDisplayPlaneAlphaFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkSurfaceTransformFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkDebugReportFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalMemoryHandleTypeFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalMemoryFeatureFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalMemoryHandleTypeFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalMemoryFeatureFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalSemaphoreHandleTypeFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalSemaphoreFeatureFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSemaphoreImportFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalFenceHandleTypeFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkExternalFenceFeatureFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkFenceImportFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkSurfaceCounterFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkPeerMemoryFeatureFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkMemoryAllocateFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDeviceGroupPresentModeFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkSwapchainCreateFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkSubgroupFeatureFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkDebugUtilsMessageSeverityFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkDebugUtilsMessageTypeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkSwapchainImageUsageFlagsANDROID): string = $toEnums(bitset)
+proc `$`*(bitset: VkSubmitFlags): string = $toEnums(bitset)
+proc `$`*(bitset: VkGraphicsPipelineLibraryFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkOpticalFlowGridSizeFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkOpticalFlowUsageFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkOpticalFlowSessionCreateFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkOpticalFlowExecuteFlagsNV): string = $toEnums(bitset)
+proc `$`*(bitset: VkPresentScalingFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkPresentGravityFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoCodecOperationFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoChromaSubsamplingFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoComponentBitDepthFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoCapabilityFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoSessionCreateFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoCodingControlFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoDecodeUsageFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoDecodeCapabilityFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoDecodeH264PictureLayoutFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeUsageFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeContentFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeCapabilityFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeRateControlModeFlagsKHR): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH264CapabilityFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH264InputModeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH264OutputModeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH265CapabilityFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH265InputModeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH265OutputModeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH265CtbSizeFlagsEXT): string = $toEnums(bitset)
+proc `$`*(bitset: VkVideoEncodeH265TransformBlockSizeFlagsEXT): string = $toEnums(bitset)
+type
   VkGeometryFlagsNV* = VkGeometryFlagsKHR
   VkGeometryInstanceFlagsNV* = VkGeometryInstanceFlagsKHR
   VkBuildAccelerationStructureFlagsNV* = VkBuildAccelerationStructureFlagsKHR
@@ -11626,4 +11895,4 @@
 
 converter VkBool2NimBool*(a: VkBool32): bool = a > 0
 converter NimBool2VkBool*(a: bool): VkBool32 = VkBool32(a)
-proc `$`*(x: uint32): string {.raises: [].} = addInt(result, x)
+proc `$`*(x: uint32): string {.raises: [].} = addInt(result, x)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/semicongine/vulkan/buffer.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -0,0 +1,31 @@
+import ./api
+
+type
+  Buffer = object
+    device: VkDevice
+    vk: VkBuffer
+    size: uint64
+
+# currently no support for extended structure and concurrent/shared use
+# (shardingMode = VK_SHARING_MODE_CONCURRENT not supported)
+proc createBuffer(device: VkDevice, size: uint64, flags: openArray[VkBufferCreateFlagBits], usage: openArray[VkBufferUsageFlagBits]): Buffer =
+  result.device = device
+  result.size = size
+  var createInfo = VkBufferCreateInfo(
+    sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+    flags: toBits(flags),
+    size: size,
+    usage: toBits(usage),
+    sharingMode: VK_SHARING_MODE_EXCLUSIVE,
+  )
+
+  checkVkResult vkCreateBuffer(
+    device=device,
+    pCreateInfo=addr createInfo,
+    pAllocator=nil,
+    pBuffer=addr result.vk
+  )
+
+proc destroy(buffer: Buffer) =
+  if uint(buffer.vk) != 0:
+    vkDestroyBuffer(buffer.device, buffer.vk, nil)
--- a/src/semicongine/vulkan/buffers.nim	Mon Feb 27 00:05:26 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-import ./api
-
-type
-  Buffer = object
-    device: VkDevice
-    vk: VkBuffer
-    size: uint64
-
-# currently no support for extended structure and concurrent/shared use
-# (shardingMode = VK_SHARING_MODE_CONCURRENT not supported)
-proc createBuffer(device: VkDevice, size: uint64, flags: openArray[VkBufferCreateFlagBits], usage: openArray[VkBufferUsageFlagBits]): Buffer =
-  result.device = device
-  result.size = size
-  var createInfo = VkBufferCreateInfo(
-    sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
-    flags: toBits(flags),
-    size: size,
-    usage: toBits(usage),
-    sharingMode: VK_SHARING_MODE_EXCLUSIVE,
-  )
-
-  checkVkResult vkCreateBuffer(
-    device=device,
-    pCreateInfo=addr createInfo,
-    pAllocator=nil,
-    pBuffer=addr result.vk
-  )
-
-proc destroy(buffer: Buffer) =
-  if uint(buffer.vk) != 0:
-    vkDestroyBuffer(buffer.device, buffer.vk, nil)
--- a/src/semicongine/vulkan/device.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/vulkan/device.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -3,48 +3,60 @@
 import ./instance
 
 type
-  PhysicalDevice = object
+  PhysicalDevice* = object
     vk: VkPhysicalDevice
-  Device = object
+  Device* = object
     physicalDevice: PhysicalDevice
     vk: VkDevice
-  QueueFamily = object
-    vk: VkQueueFamilyProperties
+  QueueFamily* = object
+    properties: VkQueueFamilyProperties
     index: uint32
-  Queue = object
+  Queue* = object
     vk: VkQueue
 
-proc getDeviceExtensions*(device: VkPhysicalDevice): seq[string] =
+proc getPhysicalDevices*(instance: Instance): seq[PhysicalDevice] =
+  assert instance.vk.valid
+  var nDevices: uint32
+  checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), nil)
+  var devices = newSeq[VkPhysicalDevice](nDevices)
+  checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), devices.toCPointer)
+  for i in 0 ..< nDevices:
+    result.add PhysicalDevice(vk: devices[i])
+
+proc getExtensions*(device: PhysicalDevice): seq[string] =
+  assert device.vk.valid
   var extensionCount: uint32
-  checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), nil)
+  checkVkResult vkEnumerateDeviceExtensionProperties(device.vk, nil, addr(extensionCount), nil)
   if extensionCount > 0:
     var extensions = newSeq[VkExtensionProperties](extensionCount)
-    checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), addr extensions[0])
+    checkVkResult vkEnumerateDeviceExtensionProperties(device.vk, nil, addr(extensionCount), extensions.toCPointer)
     for extension in extensions:
       result.add(cleanString(extension.extensionName))
 
-proc getVulkanPhysicalDevices*(instance: Instance): seq[PhysicalDevice] =
-  var nDevices: uint32
-  checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), nil)
-  var devices = newSeq[VkPhysicalDevice](nDevices)
-  checkVkResult vkEnumeratePhysicalDevices(instance.vk, addr(nDevices), addr devices[0])
-  for i in 0 ..< nDevices:
-    result.add PhysicalDevice(vk: devices[i])
-
 proc getQueueFamilies*(device: PhysicalDevice): seq[QueueFamily] =
+  assert device.vk.valid
   var nQueuefamilies: uint32
   vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies, nil)
   var queuFamilies = newSeq[VkQueueFamilyProperties](nQueuefamilies)
-  vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies , addr queuFamilies[0])
+  vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies , queuFamilies.toCPointer)
   for i in 0 ..< nQueuefamilies:
-    result.add QueueFamily(vk: queuFamilies[i], index: i)
+    result.add QueueFamily(properties: queuFamilies[i], index: i)
 
-proc createDevice(
+func canGraphics*(family: QueueFamily): bool =
+  VK_QUEUE_GRAPHICS_BIT in family.properties.queueFlags.toEnums
+func canTransfer*(family: QueueFamily): bool =
+  VK_QUEUE_TRANSFER_BIT in family.properties.queueFlags.toEnums
+func canCompute*(family: QueueFamily): bool =
+  VK_QUEUE_COMPUTE_BIT in family.properties.queueFlags.toEnums
+
+proc createDevice*(
   physicalDevice: PhysicalDevice,
   enabledLayers: openArray[string],
   enabledExtensions: openArray[string],
   queueFamilies: openArray[QueueFamily],
 ): Device =
+  assert physicalDevice.vk.valid
+  assert queueFamilies.len > 0
   result.physicalDevice = physicalDevice
   var
     enabledLayersC = allocCStringArray(enabledLayers)
@@ -62,7 +74,7 @@
   var createInfo = VkDeviceCreateInfo(
     sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
     queueCreateInfoCount: uint32(deviceQueues.len),
-    pQueueCreateInfos: addr deviceQueues[0],
+    pQueueCreateInfos: deviceQueues.toCPointer,
     enabledLayerCount: uint32(enabledLayers.len),
     ppEnabledLayerNames: enabledLayersC,
     enabledExtensionCount: uint32(enabledExtensions.len),
@@ -78,3 +90,8 @@
   )
   deallocCStringArray(enabledLayersC)
   deallocCStringArray(enabledExtensionsC)
+
+proc destroy*(device: var Device) =
+  assert device.vk.valid
+  device.vk.vkDestroyDevice(nil)
+  device.vk.reset()
--- a/src/semicongine/vulkan/instance.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/vulkan/instance.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -6,10 +6,10 @@
 type
   Instance* = object
     vk*: VkInstance
-  Debugger = object
-    instance: VkInstance
+  Debugger* = object
+    instance: Instance
     messenger: VkDebugUtilsMessengerEXT
-  DebugCallback = proc (
+  DebugCallback* = proc (
     messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT,
     messageTypes: VkDebugUtilsMessageTypeFlagsEXT,
     pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT,
@@ -18,10 +18,10 @@
 
 proc getInstanceExtensions*(): seq[string] =
   var extensionCount: uint32
-  checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), nil)
+  checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), nil)
   if extensionCount > 0:
     var extensions = newSeq[VkExtensionProperties](extensionCount)
-    checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), addr extensions[0])
+    checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), extensions.toCPointer)
     for extension in extensions:
       result.add(cleanString(extension.extensionName))
 
@@ -30,14 +30,14 @@
   checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), nil)
   if n_layers > 0:
     var layers = newSeq[VkLayerProperties](n_layers)
-    checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), addr layers[0])
+    checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), layers.toCPointer)
     for layer in layers:
       result.add(cleanString(layer.layerName))
 
 proc createInstance*(
   vulkanVersion: uint32,
-  instanceExtensions: seq[string],
-  layers: seq[string],
+  instanceExtensions: openArray[string],
+  layers: openArray[string],
   name = "defaultVulkanInstance",
   engine = "defaultEngine",
 ): Instance =
@@ -61,14 +61,17 @@
       ppEnabledExtensionNames: instanceExtensionsC
     )
   checkVkResult vkCreateInstance(addr(createinfo), nil, addr(result.vk))
+  result.vk.loadVulkan()
   deallocCStringArray(layersC)
   deallocCStringArray(instanceExtensionsC)
   for extension in instanceExtensions:
     result.vk.loadExtension($extension)
 
-proc destroy(instance: Instance) =
+proc destroy*(instance: var Instance) =
+  assert instance.vk.valid
   # needs to happen after window is trashed as the driver might have a hook registered for the window destruction
   instance.vk.vkDestroyInstance(nil)
+  instance.vk.reset()
 
 proc defaultDebugCallback(
   messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT,
@@ -79,12 +82,13 @@
   echo &"{messageSeverity}: {toEnums messageTypes}: {pCallbackData.pMessage}"
   return false
 
-proc createDebugMessenger(
-  instance: VkInstance,
+proc createDebugMessenger*(
+  instance: Instance,
   severityLevels: openArray[VkDebugUtilsMessageSeverityFlagBitsEXT] = @[],
   types: openArray[VkDebugUtilsMessageTypeFlagBitsEXT] = @[],
   callback: DebugCallback=defaultDebugCallback
 ): Debugger =
+  assert instance.vk.valid
   result.instance = instance
   var severityLevelBits = high(VkDebugUtilsMessageSeverityFlagsEXT)
   var typeBits = high(VkDebugUtilsMessageTypeFlagsEXT)
@@ -99,7 +103,10 @@
     pfnUserCallback: callback,
     pUserData: nil,
   )
-  checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result.messenger))
+  checkVkResult instance.vk.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result.messenger))
 
-proc destroy(debugger: Debugger) =
-  debugger.instance.vkDestroyDebugUtilsMessengerEXT(debugger.messenger, nil)
+proc destroy*(debugger: var Debugger) =
+  assert debugger.messenger.valid
+  assert debugger.instance.vk.valid
+  debugger.instance.vk.vkDestroyDebugUtilsMessengerEXT(debugger.messenger, nil)
+  debugger.messenger.reset()
--- a/src/semicongine/vulkan/utils.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/vulkan/utils.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -6,3 +6,5 @@
       result = join(str[0 ..< i])
       break
 
+func toCPointer*[T](list: var seq[T]): ptr T =
+  if list.len > 0: addr list[0] else: nil
--- a/src/semicongine/vulkan_helpers.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/semicongine/vulkan_helpers.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -81,8 +81,7 @@
   var n_queuefamilies: uint32
   vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), nil)
   result = newSeq[VkQueueFamilyProperties](n_queuefamilies)
-  vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies),
-      addrOrNil(result))
+  vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), addrOrNil(result))
 
 
 proc getDeviceSurfaceFormats*(device: VkPhysicalDevice,
--- a/src/vulkan_api/vulkan_api_generator.nim	Mon Feb 27 00:05:26 2023 +0700
+++ b/src/vulkan_api/vulkan_api_generator.nim	Tue Feb 28 00:08:28 2023 +0700
@@ -127,7 +127,8 @@
     result = &"array[{arraylen}, {result}]"
 
 # serializers
-func serializeEnum(node: XmlNode, api: XmlNode): seq[string] =
+# return values and whether this is a bitfield
+func serializeEnum(node: XmlNode, api: XmlNode): (seq[string], string) =
   let name = node.attr("name")
   if name == "":
     return result
@@ -206,13 +207,13 @@
       else:
         values[smartParseInt(value.attr("value"))] = value.attr("name")
     if values.len > 0:
-      result.add "  " & name & "* {.size: sizeof(cint).} = enum"
+      result[0].add "  " & name & "* {.size: sizeof(cint).} = enum"
       for (value, name) in tableSorted(values):
         var thename = name
         if name.replace("_", "").toLower() in reservedNames:
           thename = thename & "_ENUM"
         let enumEntry = &"    {thename} = {value}"
-        result.add enumEntry
+        result[0].add enumEntry
 
   # generate bitsets (normal enums in the C API, but bitfield-enums in Nim)
   elif node.attr("type") == "bitmask":
@@ -226,41 +227,42 @@
         predefined_enum_sets.add &"  {value.attr(\"name\")}* = {value.attr(\"value\")}"
 
     if values.len > 0:
+      let cApiName = name.replace("FlagBits", "Flags")
+      result[1] = cApiName
       if node.hasAttr("bitwidth"):
-        result.add "  " & name & "* {.size: 8.} = enum"
+        result[0].add "  " & name & "* {.size: 8.} = enum"
       else:
-        result.add "  " & name & "* {.size: sizeof(cint).} = enum"
+        result[0].add "  " & name & "* {.size: sizeof(cint).} = enum"
       for (bitpos, enumvalue) in tableSorted(values):
         var value = "00000000000000000000000000000000"# makes the bit mask nicely visible
         if node.hasAttr("bitwidth"): # assumes this is always 64
           value = value & value
         value[^(bitpos + 1)] = '1'
         let enumEntry = &"    {enumvalue} = 0b{value}"
-        if not (enumEntry in result): # the specs define duplicate entries for backwards compat
-          result.add enumEntry
-      let cApiName = name.replace("FlagBits", "Flags")
+        if not (enumEntry in result[0]): # the specs define duplicate entries for backwards compat
+          result[0].add enumEntry
       if node.hasAttr("bitwidth"): # assuming this attribute is always 64
         if values.len > 0:
-          result.add &"""converter BitsetToNumber*(flags: openArray[{name}]): {cApiName} =
+          result[0].add &"""func toBits*(flags: openArray[{name}]): {cApiName} =
     for flag in flags:
-      result = {cApiName}(int64(result) or int64(flag))"""
-          result.add &"""converter NumberToBitset*(number: {cApiName}): seq[{name}] =
-        for value in {name}.items:
-          if (value.ord and int64(number)) > 0:
-            result.add value"""
+      result = {cApiName}(uint64(result) or uint64(flag))"""
+          result[0].add &"""func toEnums*(number: {cApiName}): seq[{name}] =
+    for value in {name}.items:
+      if (cast[uint64](value) and uint64(number)) > 0:
+        result.add value"""
       else:
         if values.len > 0:
-          result.add &"""func toBits*(flags: openArray[{name}]): {cApiName} =
+          result[0].add &"""func toBits*(flags: openArray[{name}]): {cApiName} =
     for flag in flags:
       result = {cApiName}(uint(result) or uint(flag))"""
-          result.add &"""func toEnums*(number: {cApiName}): seq[{name}] =
+          result[0].add &"""func toEnums*(number: {cApiName}): seq[{name}] =
     for value in {name}.items:
       if (value.ord and cint(number)) > 0:
         result.add value"""
       if predefined_enum_sets.len > 0:
-        result.add "const"
-        result.add predefined_enum_sets
-      result.add "type"
+        result[0].add "const"
+        result[0].add predefined_enum_sets
+      result[0].add "type"
 
 
 func serializeStruct(node: XmlNode): seq[string] =
@@ -416,6 +418,7 @@
       "import std/tables",
       "import std/strutils",
       "import std/logging",
+      "import std/typetraits",
       "import std/macros",
       "import std/private/digitsutils",
       "from typetraits import HoleyEnum",
@@ -465,10 +468,24 @@
     if thetype.attr("category") == "bitmask" and not thetype.hasAttr("alias") and (not thetype.hasAttr("api") or thetype.attr("api") == "vulkan"):
       let name = thetype.child("name")[0].text
       outputFiles["enums"].add &"  {name}* = distinct VkFlags"
+
+  var bitfields: Table[string, string]
   outputFiles["enums"].add "let vkGetInstanceProcAddr = cast[proc(instance: VkInstance, name: cstring): pointer {.stdcall.}](checkedSymAddr(vulkanLib, \"vkGetInstanceProcAddr\"))"
   outputFiles["enums"].add "type"
   for theenum in api.findAll("enums"):
-    outputFiles["enums"].add serializeEnum(theenum, api)
+    let (enums, bitFieldName) = serializeEnum(theenum, api)
+    outputFiles["enums"].add enums
+    if bitFieldName != "":
+      bitfields[theenum.attr("name")] = bitFieldName
+
+  # bitmask-to-string functions
+  for thetype in api.findAll("type"):
+    if thetype.attr("name") in bitfields:
+      let name = bitfields[thetype.attr("name")]
+      let stringfunc = &"proc `$`*(bitset: {name}): string = $toEnums(bitset)"
+      if not (stringfunc in outputFiles["enums"]):
+        outputFiles["enums"].add stringfunc
+  outputFiles["enums"].add "type"
 
   # structs and function types need to be in same "type" block to avoid forward-declarations
   outputFiles["structs"].add serializeFunctiontypes(api)
@@ -494,6 +511,15 @@
     for thetype in typesgroup.findAll("type"):
       outputFiles.update serializeType(thetype, headerTypes)
 
+  for typesgroup in api.findAll("types"):
+    for node in typesgroup.findAll("type"):
+      if node.attr("category") == "handle":
+        if not node.hasAttr("alias"):
+          let name = node.child("name")[0].text
+          outputFiles["basetypes"].add &"proc `$`*(handle: {name}): string = \"{name}(\" & $(uint(handle)) & \")\""
+          outputFiles["basetypes"].add &"proc valid*(handle: {name}): bool = uint(handle) != 0"
+          outputFiles["basetypes"].add &"proc reset*(handle: var {name}) = handle = {name}(0)"
+
   # commands aka functions
   var varDecls: Table[string, string]
   var procLoads: Table[string, string] # procloads need to be packed into feature/extension loader procs