diff svk/generate.nim @ 1481:a99f3227130c default tip

did: continue on vulkan-api generator
author sam <sam@basx.dev>
date Sun, 27 Apr 2025 01:06:59 +0700
parents 0b302531f5c5
children
line wrap: on
line diff
--- a/svk/generate.nim	Mon Apr 21 01:31:55 2025 +0700
+++ b/svk/generate.nim	Sun Apr 27 01:06:59 2025 +0700
@@ -33,12 +33,6 @@
   "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
@@ -95,30 +89,95 @@
 
     edef.values.add EnumEntry(name: n.attr("name"), value: value)
 
+func doTypename(typename: string, isPointer: bool): string =
+  result = TYPEMAP.getOrDefault(typename.strip(), typename.strip()).strip(chars = {'_'})
+
+  if typename == "void":
+    assert isPointer
+
+  if isPointer:
+    if typename == "void":
+      result = "pointer"
+    elif typename == "char":
+      result = "cstring"
+    else:
+      result = "ptr " & result
+
+func doIdentifier(typename: string): string =
+  if typename in ["type", "object"]:
+    return &"`{typename}`"
+  return typename.strip()
+
+func doMember(typename, theType: string, isPointer: bool, value: string): string =
+  if value == "":
+    &"{doIdentifier(typename)}: {doTypename(theType, isPointer)}"
+  else:
+    &"{doIdentifier(typename)}: {doTypename(theType, isPointer)} = {value}"
+
 func memberDecl(n: XmlNode): string =
   for i in 0 ..< n.len:
     if n[i].kind == xnElement and n[i].tag == "comment":
       n.delete(i)
       break
   assert n.tag == "member"
-  debugecho n.toSeq, " ", n.len
   if n.len == 2:
-    return &"{n[1][0].text}: {n[0][0]}"
+    return doMember(n[1][0].text, n[0][0].text, false, n.attr("values"))
   elif n.len == 3:
+    assert "*" notin n[0][0].text.strip()
     if n[1].kind == xnElement and n[1].tag == "name":
-      return
-        &"{n[1][0].text}: array[{n[2].text[1 ..< ^1]}, {TYPEMAP.getOrDefault(n[0][0].text, n[0][0].text)}]]"
+      # bitfield
+      if n[2].text.strip().startsWith(":"):
+        return
+          &"{doIdentifier(n[1][0].text)} {{.bitsize:{n[2].text.strip()[1 .. ^1]}.}}: {doTypename(n[0][0].text, false)}"
+      # array definition
+      elif n[2].text.strip().startsWith("["):
+        let arrayDim = n[2].text[1 ..< ^1]
+        if "][" in arrayDim:
+          let dims = arrayDim.split("][", 1)
+          let (dim1, dim2) = (dims[0], dims[1])
+          return doMember(
+            n[1][0].text,
+            &"array[{dim1}, array[{dim2}, {doTypename(n[0][0].text, false)}]]",
+            false,
+            n.attr("values"),
+          )
+        else:
+          return doMember(
+            n[1][0].text,
+            &"array[{arrayDim}, {doTypename(n[0][0].text, false)}]",
+            false,
+            n.attr("values"),
+          )
+      else:
+        debugecho n.toSeq
+        doAssert false, "This should not happen"
     else:
+      # pointer definition
       assert n[1].text.strip() == "*"
-      return &"{n[2][0].text}: ptr {n[0][0].text}"
+      return doMember(n[2][0].text, n[0][0].text, true, n.attr("values"))
   elif n.len == 4:
     if n[0].text.strip() in ["struct", "const struct"]:
-      return &"{n[3][0].text}: ptr {n[1][0].text}"
+      return doMember(n[3][0].text, n[1][0].text, true, n.attr("values"))
     else:
+      assert n[0].text.strip() == "const" # can be ignored
+      assert n[1].tag == "type"
       assert n[2].text.strip() in ["*", "* const *", "* const*"]
-      return &"?"
+        # can be ignored, basically every type is a pointer
+      assert n[3].tag == "name"
+      assert n[1].len == 1
+      assert n[3].len == 1
+      return doMember(n[3][0].text, n[1][0].text, true, n.attr("values"))
   elif n.len in [5, 6]:
-    return &"{n[1][0].text}: array[{n[3][0].text}, {n[0][0].text}]"
+    # array definition, using const-value for array length
+    # <type>uint8_t</type>,<name>pipelineCacheUUID</name>[<enum>VK_UUID_SIZE</enum>]
+    assert n[2].text.strip() == "["
+    assert n[4].text.strip() == "]"
+    return doMember(
+      n[1][0].text,
+      &"array[{n[3][0].text}, {doTypename(n[0][0].text, false)}]",
+      false,
+      n.attr("values"),
+    )
   assert false
 
 for e in xmlenums:
@@ -152,12 +211,19 @@
         extendenum.attrs["extnumber"] = extNum
       enums[extendenum.attr("extends")].addValue(extendenum)
 
-let outPath = (system.currentSourcePath.parentDir() / "api.nim")
+let outPath = (system.currentSourcePath.parentDir() / "vkapi.nim")
 let outFile = open(outPath, fmWrite)
 
 # generate core types ===============================================================================
 # preamble, much easier to hardcode than to generate from xml
 outFile.writeLine """
+
+import ../semicongine/thirdparty/winim/winim/inc/winbase
+import ../semicongine/thirdparty/winim/winim/inc/windef
+import ../semicongine/thirdparty/x11/xlib
+import ../semicongine/thirdparty/x11/x
+import ../semicongine/thirdparty/x11/xrandr
+
 func VK_MAKE_API_VERSION*(
     variant: uint32, major: uint32, minor: uint32, patch: uint32
 ): uint32 {.compileTime.} =
@@ -166,6 +232,54 @@
 
 outFile.writeLine "type"
 outFile.writeLine """
+  # some unused native types
+  #
+  # android
+  ANativeWindow = object
+  AHardwareBuffer = object
+
+  # apple
+  CAMetalLayer = object
+  MTLDevice = object
+  MTLCommandQueue = object
+  MTLBuffer = object
+  MTLTexture = object
+  MTLSharedEvent = object
+  MTLSharedEvent_id = object
+
+  # wayland
+  wl_display = object
+  wl_surface = object
+
+  # XCB
+  xcb_connection_t = object
+  xcb_window_t = object
+  xcb_visualid_t = object
+
+  # directfb
+  IDirectFB = object
+  IDirectFBSurface = object
+
+  # Zircon
+  zx_handle_t = object
+
+  # GGP C
+  GgpStreamDescriptor = object
+  GgpFrameToken = object
+
+  # Screen (nintendo switch?)
+  screen_context = object
+  screen_window = object
+  screen_buffer = object
+
+  # Nvidia
+  NvSciSyncAttrList = object
+  NvSciSyncObj = object
+  NvSciSyncFence = object
+  NvSciBufAttrList = object
+  NvSciBufObj = object
+
+  # some base vulkan base types
   VkSampleMask = distinct uint32 
   VkBool32 = distinct uint32 
   VkFlags = distinct uint32 
@@ -175,36 +289,6 @@
   VkRemoteAddressNV = pointer
 """
 
-for t in types:
-  if t.attr("api") == "vulkansc":
-    continue
-  if t.attr("alias") != "":
-    continue
-  if t.attr("deprecated") == "true":
-    continue
-  if t.attr("category") == "include":
-    continue
-  if t.attr("category") == "define":
-    continue
-  if t.attr("category") == "bitmask":
-    if t.len > 0 and t[0].text.startsWith("typedef"):
-      outFile.writeLine &"  {t[2][0].text} = distinct {t[1][0].text}"
-  elif t.attr("category") == "union":
-    let n = t.attr("name")
-    outFile.writeLine &"  {n}* {{.union.}} = object"
-    for member in t.findAll("member"):
-      outFile.writeLine &"    {member.memberDecl()}"
-  elif t.attr("category") == "handle":
-    outFile.writeLine &"  {t[2][0].text} = distinct pointer"
-  elif t.attr("category") == "struct":
-    let n = t.attr("name")
-    outFile.writeLine &"  {n}* = object"
-    for member in t.findAll("member"):
-      outFile.writeLine &"    {member.memberDecl()}"
-  # TODO: funcpointer
-
-outFile.writeLine ""
-
 # generate consts ===============================================================================
 outFile.writeLine "const"
 for c in consts:
@@ -219,12 +303,77 @@
 outFile.writeLine ""
 
 # generate enums ===============================================================================
+const nameCollisions = [
+  "VK_PIPELINE_CACHE_HEADER_VERSION_ONE",
+  "VK_PIPELINE_CACHE_HEADER_VERSION_SAFETY_CRITICAL_ONE",
+  "VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT",
+]
 outFile.writeLine "type"
 for edef in enums.values():
   if edef.values.len > 0:
     outFile.writeLine &"  {edef.name}* {{.size: 4.}} = enum"
     for ee in edef.values:
-      outFile.writeLine &"    {ee.name} = {ee.value}"
+      # due to the nim identifier-system, there might be collisions between typenames and enum-member names
+      if ee.name in nameCollisions:
+        outFile.writeLine &"    {ee.name}_VALUE = {ee.value}"
+      else:
+        outFile.writeLine &"    {ee.name} = {ee.value}"
+
+outFile.writeLine ""
+
+# generate types ===============================================================================
+for t in types:
+  let category = t.attr("category")
+  if t.attr("api") == "vulkansc":
+    continue
+  elif t.attr("deprecated") == "true":
+    continue
+  elif category == "include":
+    continue
+  elif category == "define":
+    continue
+  elif t.attr("requires").startsWith("vk_video"):
+    continue
+  elif t.attr("alias") != "":
+    let a = t.attr("alias")
+    let n = t.attr("name")
+    outFile.writeLine &"  {n} = {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}"
+  elif category == "union":
+    let n = t.attr("name")
+    outFile.writeLine &"  {n}* {{.union.}} = object"
+    for member in t.findAll("member"):
+      outFile.writeLine &"    {member.memberDecl()}"
+  elif category == "handle":
+    outFile.writeLine &"  {t[2][0].text} = distinct pointer"
+  elif category == "struct":
+    let n = t.attr("name")
+    outFile.writeLine &"  {n}* = object"
+    for member in t.findAll("member"):
+      if member.attr("api") == "vulkansc":
+        continue
+      outFile.writeLine &"    {member.memberDecl()}"
+  elif category == "funcpointer":
+    #[
+    <type category="funcpointer">typedef void* (VKAPI_PTR *<name>PFN_vkAllocationFunction</name>)(
+      <type>void</type>*                                       pUserData,
+      <type>size_t</type>                                      size,
+      <type>size_t</type>                                      alignment,
+      <type>VkSystemAllocationScope</type>                     allocationScope);
+    </type>
+    PFN_vkAllocationFunction* = proc(
+      pUserData: pointer,
+      size: csize_t,
+      alignment: csize_t,
+      allocationScope: VkSystemAllocationScope,
+    ): pointer {.cdecl.}
+    ]#
+    assert t[0].text.startsWith("typedef ")
+    outFile.writeLine &"  {t[1][0].text}* = proc()"
+  else:
+    doAssert category in ["", "basetype", "enum"], "unknown type category: " & category
 outFile.writeLine ""
 
 outFile.writeLine """