diff svk/generate.nim @ 1479:172ac338f820 main

add: prep to add new vulkan api
author sam <sam@basx.dev>
date Sun, 20 Apr 2025 21:57:56 +0700
parents
children 0b302531f5c5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svk/generate.nim	Sun Apr 20 21:57:56 2025 +0700
@@ -0,0 +1,171 @@
+import std/strtabs
+import std/xmltree
+import std/tables
+import std/options
+import std/sequtils
+import std/strutils
+import std/strformat
+import std/xmlparser
+import std/os
+import std/paths
+
+# helpers
+func smartParseInt(value: string): int =
+  if value.startsWith("0x"):
+    parseHexInt(value)
+  else:
+    parseInt(value)
+
+const TYPEMAP = {
+  "void": "void",
+  "char": "char",
+  "float": "float32",
+  "double": "float64",
+  "int8_t": "int8",
+  "uint8_t": "uint8",
+  "int16_t": "int16",
+  "uint16_t": "uint16",
+  "int32_t": "int32",
+  "uint32_t": "uint32",
+  "uint64_t": "uint64",
+  "int64_t": "int64",
+  "size_t": "csize_t",
+  "int": "cint",
+  "void*": "pointer",
+  "char*": "cstring",
+  "ptr char": "cstring",
+  "ptr void": "pointer",
+    # "VK_DEFINE_HANDLE": "VkHandle", # not required, can directly defined as a distinct pointer, (in C is a pointer to an empty struct type)
+    # "VK_DEFINE_NON_DISPATCHABLE_HANDLE": "VkNonDispatchableHandle", # same here
+}.toTable
+
+# load xml
+let xml = (system.currentSourcePath.parentDir() / "vk.xml").loadXml()
+let platforms = xml.findAll("platforms")[0]
+let types = xml.findAll("types")[0]
+let xmlenums = xml.findAll("enums")
+let commands = xml.findAll("commands")[0]
+let features = xml.findAll("feature") # features has extends="<ENUM>"
+let extensions = xml.findAll("extensions")[0] # extensions has extends="<ENUM>"
+let formats = xml.findAll("formats")[0]
+
+# gather all enums
+
+type
+  EnumEntry = object
+    name: string
+    value: string
+
+  EnumDef = object
+    name: string
+    values: seq[EnumEntry]
+    isBitmask: bool
+
+  ConstantDef = object
+    name: string
+    datatype: string
+    value: string
+
+var consts: seq[ConstantDef]
+var enums: Table[string, EnumDef]
+
+func addValue(edef: var EnumDef, n: XmlNode) =
+  if n.attr("deprecated") != "aliased" and n.attr("alias") == "":
+    if n.attr("name") in edef.values.mapIt(it.name):
+      return
+    if n.attr("name").endsWith("_EXT") and
+        n.attr("name")[0 ..< ^4] in edef.values.mapIt(it.name):
+      return
+
+    var value = ""
+    if n.attr("value") != "":
+      value = n.attr("value")
+    elif n.attr("bitpos") != "":
+      value = $(1 shl parseInt(n.attr("bitpos")))
+    elif n.attr("offset") != "":
+      var enumBase = 1000000000
+      if n.attr("extnumber") != "":
+        enumBase += (smartParseInt(n.attr("extnumber")) - 1) * 1000
+      var v = smartParseInt(n.attr("offset")) + enumBase
+      if n.attr("dir") == "-":
+        v = -v
+      value = $(v)
+
+    edef.values.add EnumEntry(name: n.attr("name"), value: value)
+
+for e in xmlenums:
+  if e.attr("type") == "constants":
+    for c in e.findAll("enum"):
+      var value = c.attr("value").strip(chars = {'(', ')'})
+      consts.add ConstantDef(
+        name: c.attr("name"), datatype: TYPEMAP[c.attr("type")], value: value
+      )
+  elif e.attr("type") == "enum":
+    var edef = EnumDef(name: e.attr("name"), isBitmask: false)
+    for ee in e.findAll("enum"):
+      edef.addValue(ee)
+    enums[edef.name] = edef
+  elif e.attr("type") == "bitmask":
+    var edef = EnumDef(name: e.attr("name"), isBitmask: true)
+    for ee in e.findAll("enum"):
+      edef.addValue(ee)
+    enums[edef.name] = edef
+
+for f in features:
+  for extendenum in f.findAll("enum"):
+    if extendenum.attr("extends") != "":
+      enums[extendenum.attr("extends")].addValue(extendenum)
+
+for extension in extensions.findAll("extension"):
+  let extNum = extension.attr("number")
+  for extendenum in extension.findAll("enum"):
+    if extendenum.attr("extends") != "":
+      if extendenum.attr("extnumber") == "":
+        extendenum.attrs["extnumber"] = extNum
+      enums[extendenum.attr("extends")].addValue(extendenum)
+
+# generate core types ===============================================================================
+# preamble, much easier to hardcode than to generate from xml
+echo """
+when defined(linux):
+  include ./platform/xlib
+when defined(windows):
+  include ./platform/win32
+
+func 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
+
+
+"""
+
+echo "type"
+
+for t in types:
+  if t.attr("deprecated") == "true":
+    continue
+  echo t
+echo ""
+
+# generate consts ===============================================================================
+echo "const"
+for c in consts:
+  var value = c.value
+  if value.endsWith("U"):
+    value = value[0 ..^ 2] & "'u32"
+  elif value.endsWith("ULL"):
+    value = value[0 ..^ 4] & "'u64"
+  if value[0] == '~':
+    value = "not " & value[1 ..^ 1]
+  echo &"  {c.name}*: {c.datatype} = {value}"
+echo ""
+
+# generate enums ===============================================================================
+echo "type"
+for edef in enums.values():
+  if edef.values.len > 0:
+    echo &"  {edef.name}* {{.size: 4.}} = enum"
+    for ee in edef.values:
+      echo &"    {ee.name} = {ee.value}"
+echo ""