Mercurial > games > semicongine
changeset 89:6e8037c1f655
add: better vulkan wrappers
author | Sam <sam@basx.dev> |
---|---|
date | Mon, 27 Feb 2023 00:04:57 +0700 |
parents | d911cacce29e |
children | 2e9823f9193f |
files | src/semicongine/engine.nim src/semicongine/shader.nim src/semicongine/vulkan/buffers.nim src/semicongine/vulkan/device.nim src/semicongine/vulkan/instance.nim src/semicongine/vulkan/memory.nim src/semicongine/vulkan/utils.nim src/semicongine/vulkan_helpers.nim |
diffstat | 8 files changed, 286 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/src/semicongine/engine.nim Sat Feb 25 01:21:29 2023 +0700 +++ b/src/semicongine/engine.nim Mon Feb 27 00:04:57 2023 +0700 @@ -111,21 +111,17 @@ 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: getDeviceExtensions(vulkanPhysicalDevice)) vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties)) vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features)) device.formats = vulkanPhysicalDevice.getDeviceSurfaceFormats(surface) device.presentModes = vulkanPhysicalDevice.getDeviceSurfacePresentModes(surface) debug(&"Physical device nr {int(vulkanPhysicalDevice)} {cleanString(device.properties.deviceName)}") - for i, queueFamilyProperty in enumerate(getQueueFamilies( - vulkanPhysicalDevice)): + for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)): var hasSurfaceSupport: VkBool32 = VK_FALSE - checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, - uint32(i), surface, addr(hasSurfaceSupport)) - device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, - hasSurfaceSupport: bool(hasSurfaceSupport))) + checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport)) + device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, hasSurfaceSupport: bool(hasSurfaceSupport))) debug(&" Queue family {i} {queueFamilyProperty}") result.add(device) @@ -182,11 +178,9 @@ pfnUserCallback: debugCallback, pUserData: nil, ) - checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, - addr(result)) + checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result)) -proc setupVulkanDeviceAndQueues(instance: VkInstance, - surface: VkSurfaceKHR): Device = +proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): Device = let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice() if len(usableDevices) == 0: raise newException(Exception, "No suitable graphics device found") @@ -539,8 +533,7 @@ when DEBUG_LOG: result.vulkan.debugMessenger = result.vulkan.instance.setupDebugLog() result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.window) - result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues( - result.vulkan.surface) + result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface) # get basic frame information result.vulkan.surfaceFormat = result.vulkan.device.physicalDevice.formats.getSuitableSurfaceFormat() @@ -906,8 +899,7 @@ 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.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
--- a/src/semicongine/shader.nim Sat Feb 25 01:21:29 2023 +0700 +++ b/src/semicongine/shader.nim Mon Feb 27 00:04:57 2023 +0700 @@ -58,7 +58,7 @@ input = shaderSource ) - when defined(mingw) and not defined(windows): # required for crosscompilation, path separators get messed up + when defined(mingw) and defined(linux): # required for crosscompilation, path separators get messed up let shaderbinary = staticRead shaderfile.replace("\\", "/") else: let shaderbinary = staticRead shaderfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/buffers.nim Mon Feb 27 00:04:57 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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/device.nim Mon Feb 27 00:04:57 2023 +0700 @@ -0,0 +1,80 @@ +import ./api +import ./utils +import ./instance + +type + PhysicalDevice = object + vk: VkPhysicalDevice + Device = object + physicalDevice: PhysicalDevice + vk: VkDevice + QueueFamily = object + vk: VkQueueFamilyProperties + index: uint32 + Queue = object + vk: VkQueue + +proc getDeviceExtensions*(device: VkPhysicalDevice): seq[string] = + var extensionCount: uint32 + checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), nil) + if extensionCount > 0: + var extensions = newSeq[VkExtensionProperties](extensionCount) + checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), addr extensions[0]) + 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] = + var nQueuefamilies: uint32 + vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies, nil) + var queuFamilies = newSeq[VkQueueFamilyProperties](nQueuefamilies) + vkGetPhysicalDeviceQueueFamilyProperties(device.vk, addr nQueuefamilies , addr queuFamilies[0]) + for i in 0 ..< nQueuefamilies: + result.add QueueFamily(vk: queuFamilies[i], index: i) + +proc createDevice( + physicalDevice: PhysicalDevice, + enabledLayers: openArray[string], + enabledExtensions: openArray[string], + queueFamilies: openArray[QueueFamily], +): Device = + result.physicalDevice = physicalDevice + var + enabledLayersC = allocCStringArray(enabledLayers) + enabledExtensionsC = allocCStringArray(enabledExtensions) + priority = 1'f32 + var deviceQueues: seq[VkDeviceQueueCreateInfo] + for family in queueFamilies: + deviceQueues.add VkDeviceQueueCreateInfo( + sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + queueFamilyIndex: family.index, + queueCount: 1, + pQueuePriorities: addr(priority), + ) + + var createInfo = VkDeviceCreateInfo( + sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + queueCreateInfoCount: uint32(deviceQueues.len), + pQueueCreateInfos: addr deviceQueues[0], + enabledLayerCount: uint32(enabledLayers.len), + ppEnabledLayerNames: enabledLayersC, + enabledExtensionCount: uint32(enabledExtensions.len), + ppEnabledExtensionNames: enabledExtensionsC, + pEnabledFeatures: nil, + ) + + checkVkResult vkCreateDevice( + physicalDevice=physicalDevice.vk, + pCreateInfo=addr createInfo, + pAllocator=nil, + pDevice=addr result.vk + ) + deallocCStringArray(enabledLayersC) + deallocCStringArray(enabledExtensionsC)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/instance.nim Mon Feb 27 00:04:57 2023 +0700 @@ -0,0 +1,105 @@ +import std/strformat + +import ./api +import ./utils + +type + Instance* = object + vk*: VkInstance + Debugger = object + instance: VkInstance + messenger: VkDebugUtilsMessengerEXT + DebugCallback = proc ( + messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, + messageTypes: VkDebugUtilsMessageTypeFlagsEXT, + pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, + userData: pointer + ): VkBool32 {.cdecl.} + +proc getInstanceExtensions*(): seq[string] = + var extensionCount: uint32 + checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), nil) + if extensionCount > 0: + var extensions = newSeq[VkExtensionProperties](extensionCount) + checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), addr extensions[0]) + for extension in extensions: + result.add(cleanString(extension.extensionName)) + +proc getLayers*(): seq[string] = + var n_layers: uint32 + checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), nil) + if n_layers > 0: + var layers = newSeq[VkLayerProperties](n_layers) + checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), addr layers[0]) + for layer in layers: + result.add(cleanString(layer.layerName)) + +proc createInstance*( + vulkanVersion: uint32, + instanceExtensions: seq[string], + layers: seq[string], + name = "defaultVulkanInstance", + engine = "defaultEngine", +): Instance = + for i in layers: assert i in getLayers() + for i in instanceExtensions: assert i in getInstanceExtensions() + var + layersC = allocCStringArray(layers) + instanceExtensionsC = allocCStringArray(instanceExtensions) + appinfo = VkApplicationInfo( + sType: VK_STRUCTURE_TYPE_APPLICATION_INFO, + pApplicationName: name, + pEngineName: engine, + apiVersion: vulkanVersion, + ) + createinfo = VkInstanceCreateInfo( + sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + pApplicationInfo: addr(appinfo), + enabledLayerCount: layers.len.uint32, + ppEnabledLayerNames: layersC, + enabledExtensionCount: instanceExtensions.len.uint32, + ppEnabledExtensionNames: instanceExtensionsC + ) + checkVkResult vkCreateInstance(addr(createinfo), nil, addr(result.vk)) + deallocCStringArray(layersC) + deallocCStringArray(instanceExtensionsC) + for extension in instanceExtensions: + result.vk.loadExtension($extension) + +proc destroy(instance: Instance) = + # needs to happen after window is trashed as the driver might have a hook registered for the window destruction + instance.vk.vkDestroyInstance(nil) + +proc defaultDebugCallback( + messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, + messageTypes: VkDebugUtilsMessageTypeFlagsEXT, + pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, + userData: pointer +): VkBool32 {.cdecl.} = + echo &"{messageSeverity}: {toEnums messageTypes}: {pCallbackData.pMessage}" + return false + +proc createDebugMessenger( + instance: VkInstance, + severityLevels: openArray[VkDebugUtilsMessageSeverityFlagBitsEXT] = @[], + types: openArray[VkDebugUtilsMessageTypeFlagBitsEXT] = @[], + callback: DebugCallback=defaultDebugCallback +): Debugger = + result.instance = instance + var severityLevelBits = high(VkDebugUtilsMessageSeverityFlagsEXT) + var typeBits = high(VkDebugUtilsMessageTypeFlagsEXT) + if severityLevels.len > 0: + severityLevelBits = toBits severityLevels + if types.len > 0: + typeBits = toBits types + var createInfo = VkDebugUtilsMessengerCreateInfoEXT( + sType: VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + messageSeverity: severityLevelBits, + messageType: typeBits, + pfnUserCallback: callback, + pUserData: nil, + ) + checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result.messenger)) + +proc destroy(debugger: Debugger) = + debugger.instance.vkDestroyDebugUtilsMessengerEXT(debugger.messenger, nil)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/memory.nim Mon Feb 27 00:04:57 2023 +0700 @@ -0,0 +1,51 @@ +import ./api + +type + MemoryHeap = object + size: uint64 + flags: seq[VkMemoryHeapFlagBits] + index: uint32 + MemoryType = object + heap: MemoryHeap + flags: seq[VkMemoryPropertyFlagBits] + index: uint32 + PhyscialDeviceMemoryProperties = object + heaps: seq[MemoryHeap] + types: seq[MemoryType] + DeviceMemory = object + device: VkDevice + size: uint64 + vk: VkDeviceMemory + +proc getPhysicalDeviceMemoryProperties(physicalDevice: VkPhysicalDevice): PhyscialDeviceMemoryProperties = + var physicalProperties: VkPhysicalDeviceMemoryProperties + vkGetPhysicalDeviceMemoryProperties(physicalDevice, addr physicalProperties) + for i in 0 ..< physicalProperties.memoryHeapCount: + result.heaps.add MemoryHeap( + size: physicalProperties.memoryHeaps[i].size, + flags: toEnums(physicalProperties.memoryHeaps[i].flags), + index: i, + ) + for i in 0 ..< physicalProperties.memoryTypeCount: + result.types.add MemoryType( + heap: result.heaps[physicalProperties.memoryTypes[i].heapIndex], + flags: toEnums(physicalProperties.memoryTypes[i].propertyFlags), + index: i, + ) + +proc allocateMemory(device: VkDevice, size: uint64, memoryType: MemoryType): DeviceMemory = + result.device = device + result.size = size + + var allocationInfo = VkMemoryAllocateInfo( + sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + allocationSize: size, + memoryTypeIndex: memoryType.index, + ) + + checkVkResult vkAllocateMemory( + device, + addr allocationInfo, + nil, + addr result.vk + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/semicongine/vulkan/utils.nim Mon Feb 27 00:04:57 2023 +0700 @@ -0,0 +1,8 @@ +import std/strutils + +func cleanString*(str: openArray[char]): string = + for i in 0 ..< len(str): + if str[i] == char(0): + result = join(str[0 ..< i]) + break +
--- a/src/semicongine/vulkan_helpers.nim Sat Feb 25 01:21:29 2023 +0700 +++ b/src/semicongine/vulkan_helpers.nim Mon Feb 27 00:04:57 2023 +0700 @@ -40,11 +40,9 @@ proc getInstanceExtensions*(): seq[string] = var extensionCount: uint32 - checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( - extensionCount), nil) + checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), nil) var extensions = newSeq[VkExtensionProperties](extensionCount) - checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( - extensionCount), addrOrNil(extensions)) + checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), addrOrNil(extensions)) for extension in extensions: result.add(cleanString(extension.extensionName)) @@ -177,7 +175,6 @@ for extension in requiredExtensions & other_extensions: result.loadExtension($extension) - proc getVulcanDevice*( physicalDevice: var VkPhysicalDevice, features: var VkPhysicalDeviceFeatures,