Mercurial > games > semicongine
diff semicongine/vulkan/instance.nim @ 840:44ec744fbedc
did: package restructuring according to nimble recommendation for libraries
author | Sam <sam@basx.dev> |
---|---|
date | Sat, 02 Dec 2023 22:23:29 +0700 |
parents | |
children | 904e0a827ef3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/semicongine/vulkan/instance.nim Sat Dec 02 22:23:29 2023 +0700 @@ -0,0 +1,143 @@ +import std/strformat +import std/tables +import std/sequtils +import std/logging + +import ../core + +import ../platform/vulkanExtensions +import ../platform/window +import ../platform/surface + +type + Instance* = object + vk*: VkInstance + window*: NativeWindow + surface*: VkSurfaceKHR + Debugger* = object + instance*: Instance + 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), extensions.toCPointer) + 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), layers.toCPointer) + for layer in layers: + result.add(cleanString(layer.layerName)) + +proc createInstance*( + window: NativeWindow, + vulkanVersion: uint32, + instanceExtensions: seq[string], + layers: seq[string], + name = "defaultVulkanInstance", + engine = "defaultEngine", +): Instance = + + let requiredExtensions = REQUIRED_PLATFORM_EXTENSIONS & @["VK_KHR_surface"] & instanceExtensions + for i in requiredExtensions: + assert i in getInstanceExtensions(), $i + var availableLayers: seq[string] + for i in layers: + if i in getLayers(): + availableLayers.add i + debug "Enabled layers: " & $availableLayers + var + layersC = allocCStringArray(availableLayers) + instanceExtensionsC = allocCStringArray(requiredExtensions) + 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: availableLayers.len.uint32, + ppEnabledLayerNames: layersC, + enabledExtensionCount: requiredExtensions.len.uint32, + ppEnabledExtensionNames: instanceExtensionsC + ) + checkVkResult vkCreateInstance(addr(createinfo), nil, addr(result.vk)) + result.vk.loadVulkan() + deallocCStringArray(layersC) + deallocCStringArray(instanceExtensionsC) + for extension in requiredExtensions: + result.vk.loadExtension($extension) + result.surface = result.vk.createNativeSurface(window) + +proc destroy*(instance: var Instance) = + assert instance.vk.valid + assert instance.surface.valid + # needs to happen after window is trashed as the driver might have a hook registered for the window destruction + instance.vk.vkDestroySurfaceKHR(instance.surface, nil) + instance.surface.reset() + instance.vk.vkDestroyInstance(nil) + instance.vk.reset() + +const LEVEL_MAPPING = { + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: lvlDebug, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: lvlInfo, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: lvlWarn, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: lvlError, +}.toTable + +proc defaultDebugCallback( + messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, + messageTypes: VkDebugUtilsMessageTypeFlagsEXT, + pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, + userData: pointer +): VkBool32 {.cdecl.} = + + log LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}" + if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + echo getStackTrace() + quit() + return false + +proc createDebugMessenger*( + instance: Instance, + severityLevels: openArray[VkDebugUtilsMessageSeverityFlagBitsEXT] = @[], + types: openArray[VkDebugUtilsMessageTypeFlagBitsEXT] = @[], + callback: DebugCallback=defaultDebugCallback +): Debugger = + assert instance.vk.valid + result.instance = instance + var severityLevelBits = VkDebugUtilsMessageSeverityFlagBitsEXT.items.toSeq.toBits + var typeBits = VkDebugUtilsMessageTypeFlagBitsEXT.items.toSeq.toBits + 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.vk.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result.messenger)) + +proc destroy*(debugger: var Debugger) = + assert debugger.messenger.valid + assert debugger.instance.vk.valid + debugger.instance.vk.vkDestroyDebugUtilsMessengerEXT(debugger.messenger, nil) + debugger.messenger.reset()