diff src/vulkan_helpers.nim @ 2:213fdf8d31dd

did: hello world triangle, a bit of code organization
author Sam <sam@basx.dev>
date Mon, 19 Dec 2022 10:41:20 +0700
parents bb2a7d3a7003
children af9183acb173
line wrap: on
line diff
--- a/src/vulkan_helpers.nim	Fri Dec 16 00:05:41 2022 +0700
+++ b/src/vulkan_helpers.nim	Mon Dec 19 10:41:20 2022 +0700
@@ -1,26 +1,43 @@
 import std/tables
 import std/strutils
+import std/strformat
+import std/logging
 
 import ./glslang/glslang
 import ./vulkan
 
-
 when defined(release):
-  const ENABLEVULKANVALIDATIONLAYERS = false
+  const ENABLEVULKANVALIDATIONLAYERS* = false
 else:
-  const ENABLEVULKANVALIDATIONLAYERS = true
+  const ENABLEVULKANVALIDATIONLAYERS* = true
 
 
 template checkVkResult*(call: untyped) =
-  let value = call
-  if value != VK_SUCCESS:
-    raise newException(Exception, "Vulkan error: " & astToStr(call) & " returned " & $value)
+  when defined(release):
+    discard call
+  else:
+    let value = call
+    debug(&"CALLING vulkan: {astToStr(call)}")
+    if value != VK_SUCCESS:
+      raise newException(Exception, "Vulkan error: " & astToStr(call) & " returned " & $value)
 
 
 proc VK_MAKE_API_VERSION*(variant: uint32, major: uint32, minor: uint32, patch: uint32): uint32 {.compileTime.} =
   (variant shl 29) or (major shl 22) or (minor shl 12) or patch
 
 
+proc filterForSurfaceFormat*(formats: seq[VkSurfaceFormatKHR]): seq[VkSurfaceFormatKHR] =
+  for format in formats:
+    if format.format == VK_FORMAT_B8G8R8A8_SRGB and format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
+      result.add(format)
+
+
+proc cleanString*(str: openArray[char]): string =
+  for i in 0 ..< len(str):
+    if str[i] == char(0):
+      result = join(str[0 ..< i])
+      break
+
 proc getInstanceExtensions*(): seq[string] =
   var extensionCount: uint32
   checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), nil)
@@ -28,7 +45,7 @@
   checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), addr(extensions[0]))
 
   for extension in extensions:
-    result.add(join(extension.extensionName).strip(chars={char(0)}))
+    result.add(cleanString(extension.extensionName))
 
 
 proc getDeviceExtensions*(device: VkPhysicalDevice): seq[string] =
@@ -38,7 +55,7 @@
   checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), addr(extensions[0]))
 
   for extension in extensions:
-    result.add(join(extension.extensionName).strip(chars={char(0)}))
+    result.add(cleanString(extension.extensionName))
 
 
 proc getValidationLayers*(): seq[string] =
@@ -48,7 +65,7 @@
   checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), addr(layers[0]))
 
   for layer in layers:
-    result.add(join(layer.layerName).strip(chars={char(0)}))
+    result.add(cleanString(layer.layerName))
 
 
 proc getVulkanPhysicalDevices*(instance: VkInstance): seq[VkPhysicalDevice] =
@@ -88,10 +105,10 @@
 
 proc getPresentMode*(modes: seq[VkPresentModeKHR]): VkPresentModeKHR =
   let preferredModes = [
-    VK_PRESENT_MODE_MAILBOX_KHR,
-    VK_PRESENT_MODE_FIFO_RELAXED_KHR,
-    VK_PRESENT_MODE_FIFO_KHR,
-    VK_PRESENT_MODE_IMMEDIATE_KHR,
+    VK_PRESENT_MODE_MAILBOX_KHR, # triple buffering
+    VK_PRESENT_MODE_FIFO_RELAXED_KHR, # double duffering
+    VK_PRESENT_MODE_FIFO_KHR, # double duffering
+    VK_PRESENT_MODE_IMMEDIATE_KHR, # single buffering
   ]
   for preferredMode in preferredModes:
     for mode in modes:
@@ -108,6 +125,7 @@
     "VK_KHR_display".cstring,
     "VK_KHR_surface".cstring,
     "VK_KHR_xlib_surface".cstring,
+    "VK_EXT_debug_utils".cstring,
   ]
   let availableExtensions = getInstanceExtensions()
   for extension in requiredExtensions:
@@ -122,7 +140,9 @@
       if $layer in availableLayers:
         usableLayers.add(layer)
 
+  echo "Available validation layers: ", availableLayers
   echo "Using validation layers: ", usableLayers
+  echo "Available extensions: ", availableExtensions
   echo "Using extensions: ", requiredExtensions
 
   var appinfo = VkApplicationInfo(
@@ -144,33 +164,40 @@
   loadVK_KHR_surface()
   loadVK_KHR_xlib_surface()
   loadVK_KHR_swapchain()
+  when ENABLEVULKANVALIDATIONLAYERS:
+    loadVK_EXT_debug_utils(result)
 
 
 proc getVulcanDevice*(
   physicalDevice: var VkPhysicalDevice,
   features: var VkPhysicalDeviceFeatures,
-  selectedQueueFamily: uint32,
-): (VkDevice, VkQueue) =
+  graphicsQueueFamily: uint32,
+  presentationQueueFamily: uint32,
+): (VkDevice, VkQueue, VkQueue) =
   # setup queue and device
+  # TODO: need check this, possibly wrong logic, see Vulkan tutorial
   var priority = 1.0'f32
-  var queueCreateInfo = VkDeviceQueueCreateInfo(
-    sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
-    queueFamilyIndex: uint32(selectedQueueFamily),
-    queueCount: 1,
-    pQueuePriorities: addr(priority),
-  )
+  var queueCreateInfo = [
+    VkDeviceQueueCreateInfo(
+      sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+      queueFamilyIndex: graphicsQueueFamily,
+      queueCount: 1,
+      pQueuePriorities: addr(priority),
+    ),
+  ]
 
   var requiredExtensions = ["VK_KHR_swapchain".cstring]
   var deviceCreateInfo = VkDeviceCreateInfo(
     sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-    pQueueCreateInfos: addr(queueCreateInfo),
-    queueCreateInfoCount: 1,
+    queueCreateInfoCount: uint32(queueCreateInfo.len),
+    pQueueCreateInfos: addr(queueCreateInfo[0]),
     pEnabledFeatures: addr(features),
     enabledExtensionCount: requiredExtensions.len.uint32,
     ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(requiredExtensions))
   )
   checkVkResult vkCreateDevice(physicalDevice, addr(deviceCreateInfo), nil, addr(result[0]))
-  vkGetDeviceQueue(result[0], selectedQueueFamily, 0'u32, addr(result[1]));
+  vkGetDeviceQueue(result[0], graphicsQueueFamily, 0'u32, addr(result[1]));
+  vkGetDeviceQueue(result[0], presentationQueueFamily, 0'u32, addr(result[2]));
 
 proc createShaderStage*(device: VkDevice, stage: VkShaderStageFlagBits, shader: string): VkPipelineShaderStageCreateInfo =
   const VK_GLSL_MAP = {
@@ -180,15 +207,24 @@
   var code = compileGLSLToSPIRV(VK_GLSL_MAP[stage], shader, "<memory-shader>")
   var createInfo = VkShaderModuleCreateInfo(
     sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
-    codeSize: code.len.uint,
+    codeSize: uint(code.len * sizeof(uint32)),
     pCode: addr(code[0]),
   )
   var shaderModule: VkShaderModule
   checkVkResult vkCreateShaderModule(device, addr(createInfo), nil, addr(shaderModule))
 
-  var vertShaderStageInfo = VkPipelineShaderStageCreateInfo(
+  return VkPipelineShaderStageCreateInfo(
     sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
     stage: stage,
     module: shaderModule,
     pName: "main", # entry point for shader
   )
+
+proc debugCallback*(
+  messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT,
+  messageTypes: VkDebugUtilsMessageTypeFlagsEXT,
+  pCallbackData: VkDebugUtilsMessengerCallbackDataEXT,
+  userData: pointer
+): VkBool32 {.cdecl.} =
+  echo &"{messageSeverity}: {VkDebugUtilsMessageTypeFlagBitsEXT(messageTypes)}: {pCallbackData.pMessage}"
+  return VK_FALSE