Mercurial > games > semicongine
changeset 1486:0ba3f0b2be2e default tip main
did: more
author | sam <sam@basx.dev> |
---|---|
date | Sat, 03 May 2025 20:16:04 +0700 |
parents | 6e062a84c157 |
children | |
files | svk/api.nim svk/generate.nim |
diffstat | 2 files changed, 130 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/svk/api.nim Sat May 03 01:03:01 2025 +0700 +++ b/svk/api.nim Sat May 03 20:16:04 2025 +0700 @@ -1,8 +1,11 @@ import std/strutils import std/logging +import std/os include ./vkapi +const VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 3, 0) + template checkVkResult*(call: untyped) = when defined(release): discard call @@ -21,36 +24,91 @@ type SVkInstance* = object vkInstance: VkInstance + debugMessenger: VkDebugUtilsMessengerEXT proc `=copy`(a: var SVkInstance, b: SVkInstance) {.error.} proc `=destroy`(a: SVkInstance) = if a.vkInstance.pointer != nil: + if a.debugMessenger.pointer != nil: + vkDestroyDebugUtilsMessengerEXT(a.vkInstance, a.debugMessenger, nil) a.vkInstance.vkDestroyInstance(nil) +proc debugCallback( + messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, + messageTypes: VkDebugUtilsMessageTypeFlagsEXT, + pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT, + userData: pointer, +): VkBool32 {.cdecl.} = + const LOG_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 + log LOG_LEVEL_MAPPING[messageSeverity] + if messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + # stderr.write getStackTrace() + # stderr.writeLine LOG_LEVEL_MAPPING[messageSeverity], &"{toEnums messageTypes}: {pCallbackData.pMessage}" + let errorMsg = $pCallbackData.pMessage & ": " & getStackTrace() + raise newException(Exception, errorMsg) + return VK_FALSE + proc svkCreateInstance*( applicationName: string, enabledLayers: openArray[string] = [], - enabledExtensions: openArray[string] = [], + enabledExtensions: openArray[string] = + if defined(release): + @["VK_KHR_surface"] + else: + @["VK_KHR_surface", "VK_EXT_debug_utils"], engineName = "semicongine", - majorVersion = 1'u32, - minorVersion = 3'u32, + withSwapchain = true, ): SVkInstance = + putEnv("VK_LOADER_LAYERS_ENABLE", "*validation") + putEnv( + "VK_LAYER_ENABLES", + "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT", + ) + initVulkanLoader() + let appinfo = VkApplicationInfo( pApplicationName: applicationName, pEngineName: engineName, - apiVersion: VK_MAKE_API_VERSION(0, majorVersion, minorVersion, 0), + apiVersion: VULKAN_VERSION, ) - layersC = enabledLayers.allocCStringArray() - extensionsC = enabledLayers.allocCStringArray() + enabledLayersC = allocCStringArray(enabledLayers) + enabledExtensionsC = allocCStringArray(enabledExtensions) createinfo = VkInstanceCreateInfo( pApplicationInfo: addr appinfo, enabledLayerCount: enabledLayers.len.uint32, - ppEnabledLayerNames: layersC, + ppEnabledLayerNames: enabledLayersC, enabledExtensionCount: enabledExtensions.len.uint32, - ppEnabledExtensionNames: extensionsC, + ppEnabledExtensionNames: enabledExtensionsC, ) + # this one we will load manually checkVkResult vkCreateInstance(addr createinfo, nil, addr result.vkInstance) - layersC.deallocCStringArray() - extensionsC.deallocCStringArray() + + enabledLayersC.deallocCStringArray() + enabledExtensionsC.deallocCStringArray() + + load_VK_VERSION_1_0(result.vkInstance) + load_VK_VERSION_1_1(result.vkInstance) + load_VK_VERSION_1_2(result.vkInstance) + load_VK_VERSION_1_3(result.vkInstance) + + for extension in enabledExtensions: + loadExtension(result.vkInstance, extension) + if withSwapchain: + load_VK_KHR_swapchain(result.vkInstance) + + when not defined(release): + var debugMessengerCreateInfo = VkDebugUtilsMessengerCreateInfoEXT( + messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT.items.toSeq.toBits, + messageType: VkDebugUtilsMessageTypeFlagBitsEXT.items.toSeq.toBits, + pfnUserCallback: debugCallback, + ) + checkVkResult vkCreateDebugUtilsMessengerEXT( + result.vkInstance, addr debugMessengerCreateInfo, nil, addr result.debugMessenger + )
--- a/svk/generate.nim Sat May 03 01:03:01 2025 +0700 +++ b/svk/generate.nim Sat May 03 20:16:04 2025 +0700 @@ -213,8 +213,15 @@ if extendenum.attr("extends") != "": enums[extendenum.attr("extends")].addValue(extendenum) +var extensionLoaders: seq[(string, seq[string])] + for extension in extensions.findAll("extension"): let extNum = extension.attr("number") + extensionLoaders.add (extension.attr("name"), newSeq[string]()) + for c in extension.findAll("command"): + if "Video" notin c.attr("name"): + extensionLoaders[^1][1].add c.attr("name") + for extendenum in extension.findAll("enum"): if extendenum.attr("extends") != "": if extendenum.attr("extnumber") == "": @@ -229,6 +236,8 @@ outFile.writeLine """ import std/dynlib +import std/strutils +import std/tables import ../semicongine/thirdparty/winim/winim/inc/winbase import ../semicongine/thirdparty/winim/winim/inc/windef @@ -311,7 +320,10 @@ value = value[0 ..^ 4] & "'u64" if value[0] == '~': value = "not " & value[1 ..^ 1] - outFile.writeLine &" {c.name}*: {c.datatype} = {value}" + if c.name in ["VK_TRUE", "VK_FALSE"]: + outFile.writeLine &" {c.name}*: VkBool32 = VkBool32({value})" + else: + outFile.writeLine &" {c.name}*: {c.datatype} = {value}" outFile.writeLine "" # generate enums =============================================================================== @@ -335,6 +347,7 @@ outFile.writeLine "" # generate types =============================================================================== +var stringConverters: seq[string] for t in types: let category = t.attr("category") let tName = t.attr("name") @@ -357,13 +370,14 @@ outFile.writeLine &" {tName}* = {a}" elif category == "bitmask": if t.len > 0 and t[0].text.startsWith("typedef"): - outFile.writeLine &" {t[2][0].text}* = distinct {t[1][0].text}" + outFile.writeLine &" {t[2][0].text.strip()}* = distinct {t[1][0].text.strip()}" elif category == "union": outFile.writeLine &" {tName}* {{.union.}} = object" for member in t.findAll("member"): outFile.writeLine &" {member.memberDecl()}" elif category == "handle": - outFile.writeLine &" {t[2][0].text} = distinct pointer" + outFile.writeLine &" {t[2][0].text.strip()} = distinct pointer" + stringConverters.add t[2][0].text.strip() elif category == "struct": outFile.writeLine &" {tName}* = object" for member in t.findAll("member"): @@ -451,27 +465,37 @@ outFile.write " {.stdcall.}\n" outFile.write """ -when defined(linux): - let vulkanLib = loadLib("libvulkan.so.1") -when defined(windows): - let vulkanLib = loadLib("vulkan-1.dll") -if vulkanLib == nil: - raise newException(Exception, "Unable to load vulkan library") - -vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring, ): PFN_vkVoidFunction {.stdcall.}](checkedSymAddr(vulkanLib, "vkGetInstanceProcAddr")) proc loadFunc[T](instance: VkInstance, f: var T, name: string) = f = cast[T](vkGetInstanceProcAddr(instance, name)) +proc initVulkanLoader*() = + if vkGetInstanceProcAddr != nil: + return + + when defined(linux): + let vulkanLib = loadLib("libvulkan.so.1") + when defined(windows): + let vulkanLib = loadLib("vulkan-1.dll") + if vulkanLib == nil: + raise newException(Exception, "Unable to load vulkan library") + + # init two global functions + vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring, ): PFN_vkVoidFunction {.stdcall.}](checkedSymAddr(vulkanLib, "vkGetInstanceProcAddr")) + + loadFunc(VkInstance(nil), vkCreateInstance, "vkCreateInstance") + """ for f in features: let name = f.attr("name").replace(",", "_") if f.attr("struct") != "": continue - outFile.writeLine &"proc loadFeature_{name}(instance: VkInstance) =" + outFile.writeLine &"proc load_{name}(instance: VkInstance) =" var hasEntries = false for cmd in f.findAll("command"): + if cmd.attr("name") == "vkCreateInstance": + continue hasEntries = true let cName = cmd.attr("name") outFile.writeLine &" loadFunc(instance, {cName}, \"{cName}\")" @@ -479,6 +503,32 @@ outFile.writeLine " discard" outFile.writeLine "" +for (extName, commands) in extensionLoaders: + outFile.writeLine &"proc load_{extName}(instance: VkInstance) =" + for c in commands: + outFile.writeLine &" loadFunc(instance, {c}, \"{c}\")" + if commands.len == 0: + outFile.writeLine &" discard" +outFile.writeLine "" + +outFile.writeLine "const EXTENSION_LOADERS = {" +for (extName, commands) in extensionLoaders: + outFile.writeLine &" \"{extName}\": load_{extName}," +outFile.writeLine "}.toTable" +outFile.writeLine "" + +outFile.writeLine "proc loadExtension*(instance: VkInstance, name: string) =" +outFile.writeLine " assert name in EXTENSION_LOADERS" +outFile.writeLine " EXTENSION_LOADERS[name](instance)" +outFile.writeLine "" + +for strCon in stringConverters: + outFile.writeLine &"""proc `$`*(v: {strCon}): string = "0x" & cast[uint](v).toHex()""" +outFile.writeLine "" + +# we preload the vkCreateInstance function, so we can create an instance +outFile.writeLine "" + outFile.close() assert execCmd("nim c " & outPath) == 0