diff fuhtark_test/generate_vulkan_api.sh @ 1501:f40d9d814c08 default tip

did: correct vulkan-api generator
author sam <sam@basx.dev>
date Wed, 26 Nov 2025 23:34:29 +0700
parents 91c8c3b7cbf0
children
line wrap: on
line diff
--- a/fuhtark_test/generate_vulkan_api.sh	Wed Nov 26 21:36:48 2025 +0700
+++ b/fuhtark_test/generate_vulkan_api.sh	Wed Nov 26 23:34:29 2025 +0700
@@ -1,21 +1,31 @@
 #!/bin/sh -e
 
 # Variables
-BASE_INCLUDE=$( realpath $( dirname $0 ) )"/include"
-WIN_INCLUDE=$( realpath $( dirname $0 ) )"/include/winapi"
+VULKAN_VERSION=1.4.334
+HOME_DIR=$( realpath $( dirname $0 ) )
+BASE_INCLUDE="$HOME_DIR/include"
+WIN_INCLUDE="$HOME_DIR/include/winapi"
+VULKAN_INCLUDE="$HOME_DIR/Vulkan-Headers-$VULKAN_VERSION/include/vulkan"
 OUT_BIN=vulkan
 OUTFILE=$OUT_BIN.nim
 OUTFILE_FUTHARK=$OUT_BIN".gen.nim"
 
+# setup
+# sudo apt install clang libclang-dev
+# nimble install futhark
+# rm -rf Vulkan-Headers-$VULKAN_VERSION
+# curl -L https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v$VULKAN_VERSION.tar.gz | tar -xzf -
+
 # Convert C-headers to Nim using Futhark, if not existing yet
 NIM_GEN_CODE='import futhark, os
 importc:
   outputPath "'"$OUTFILE_FUTHARK"'"
   define VK_USE_PLATFORM_WIN32_KHR
   define VK_USE_PLATFORM_XLIB_KHR
+  define VK_ENABLE_BETA_EXTENSIONS
   sysPath "'"$BASE_INCLUDE"'"
   sysPath "'"$WIN_INCLUDE"'"
-  path "/usr/include/vulkan"
+  path "'"$VULKAN_INCLUDE"'"
   "vulkan.h"'
 
 if [ ! -f $OUTFILE_FUTHARK ] ; then
@@ -36,14 +46,17 @@
 
 # set default struct values for member "sType"
 # not very clean, as we "abuse" the fact that Nim does not differentiate between camel-case and snake-case for identifiers
+
+# VkStructureType_1124073999 = (when declared(VkStructureType):
+TYPESTRUCTNAME=$( cat $OUTFILE | awk '/enum_VkStructureType\* =/ { print $3; }' )
 awk -i inplace '{
-        if ( $0 ~ /^  struct_Vk.* = object/ && ! $0 ~ /VkBaseInStructure/ ) {
+        if ( $0 ~ /^  struct_Vk.* = object/ && $0 !~ /VkBaseInStructure/ && $0 !~ /VkBaseOutStructure/ ) {
                 split($0, arr, "_");
                 print $0;
                 getline;
                 if ( $0 ~ / sType\*:/ ) {
                         split($0, arr2, "##");
-                        print arr2[1] "= VK_STRUCTURE_TYPE_" substr(arr[2], 3) " ##" arr2[2];
+                        print "    sType*: '$TYPESTRUCTNAME' = '$TYPESTRUCTNAME'.VK_STRUCTURE_TYPE_" substr(arr[2], 3) " ##" arr2[2];
                 } else {
                         print;
                 }
@@ -61,6 +74,7 @@
 import std/dynlib
 import std/strutils
 import std/logging
+import std/envvars
 
 var vkInstance*: VkInstance = VkInstance(nil)
 var vkPhysicalDevices: seq[VkPhysicalDevice]
@@ -84,6 +98,19 @@
 proc loadFunc[T](instance: VkInstance, f: var T, name: string) =
   f = cast[T](vkGetInstanceProcAddr(instance, name))
 
+proc hasValidationLayer*(): bool =
+  const val_layer = "VK_LAYER_KHRONOS_validation"
+  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:
+      let layerName = \$(cast[cstring](addr layer.layerName[0]))
+      if layerName.startsWith(val_layer):
+        return true
+  return false
+
 proc initVulkan*() =
   if vkGetInstanceProcAddr != nil:
     return
@@ -100,14 +127,43 @@
 
   # need to create an instance before loading other function points
   loadFunc(vkInstance, vkCreateInstance, "vkCreateInstance")
+  # and this one, to check which layers are available for instance creation
+  loadFunc(vkInstance, vkEnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties")
+
+  # extensions
+  var extensions = @["VK_KHR_surface"]
+  when not defined(release):
+    extensions.add "VK_EXT_debug_utils"
+  when defined(windows):
+    extensions.add "VK_KHR_win32_surface"
+  when defined(linux):
+    extensions.add "VK_KHR_xlib_surface"
+  let extensionsC = allocCStringArray(extensions)
+  defer: deallocCStringArray(extensionsC)
+
+  # layers
+  var layers: seq[string]
+  when not defined(release):
+    if hasValidationLayer():
+      layers.add "VK_LAYER_KHRONOS_validation"
+  var layersC = allocCStringArray(layers)
+  defer: deallocCStringArray(layersC)
+
+  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",
+  )
+
+  echo "Use instance extensions: ", extensions
+  echo "Use layers: ", layers
   let createInfo = VkInstanceCreateInfo(
     pNext: nil,
     flags: 0,
     pApplicationInfo: nil,
-    enabledLayerCount: 0,
-    ppEnabledLayerNames: nil,
-    enabledExtensionCount: 0,
-    ppEnabledExtensionNames: nil,
+    enabledLayerCount: layers.len.uint32,
+    ppEnabledLayerNames: cast[ptr cstring](layersC),
+    enabledExtensionCount: extensions.len.uint32,
+    ppEnabledExtensionNames: cast[ptr cstring](extensionsC),
   )
   checkVkResult vkCreateInstance(addr createInfo, nil, addr vkInstance)