Mercurial > games > semicongine
annotate svk/generate.nim @ 1480:0b302531f5c5
did: continue on vulkan nim api generator
| author | sam <sam@basx.dev> |
|---|---|
| date | Mon, 21 Apr 2025 01:31:55 +0700 |
| parents | 172ac338f820 |
| children | a99f3227130c |
| rev | line source |
|---|---|
| 1479 | 1 import std/strtabs |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
2 import std/syncio |
| 1479 | 3 import std/xmltree |
| 4 import std/tables | |
| 5 import std/options | |
| 6 import std/sequtils | |
| 7 import std/strutils | |
| 8 import std/strformat | |
| 9 import std/xmlparser | |
| 10 import std/os | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
11 import std/osproc |
| 1479 | 12 import std/paths |
| 13 | |
| 14 # helpers | |
| 15 func smartParseInt(value: string): int = | |
| 16 if value.startsWith("0x"): | |
| 17 parseHexInt(value) | |
| 18 else: | |
| 19 parseInt(value) | |
| 20 | |
| 21 const TYPEMAP = { | |
| 22 "void": "void", | |
| 23 "char": "char", | |
| 24 "float": "float32", | |
| 25 "double": "float64", | |
| 26 "int8_t": "int8", | |
| 27 "uint8_t": "uint8", | |
| 28 "int16_t": "int16", | |
| 29 "uint16_t": "uint16", | |
| 30 "int32_t": "int32", | |
| 31 "uint32_t": "uint32", | |
| 32 "uint64_t": "uint64", | |
| 33 "int64_t": "int64", | |
| 34 "size_t": "csize_t", | |
| 35 "int": "cint", | |
| 36 "void*": "pointer", | |
| 37 "char*": "cstring", | |
| 38 "ptr char": "cstring", | |
| 39 "ptr void": "pointer", | |
| 40 # "VK_DEFINE_HANDLE": "VkHandle", # not required, can directly defined as a distinct pointer, (in C is a pointer to an empty struct type) | |
| 41 # "VK_DEFINE_NON_DISPATCHABLE_HANDLE": "VkNonDispatchableHandle", # same here | |
| 42 }.toTable | |
| 43 | |
| 44 # load xml | |
| 45 let xml = (system.currentSourcePath.parentDir() / "vk.xml").loadXml() | |
| 46 let platforms = xml.findAll("platforms")[0] | |
| 47 let types = xml.findAll("types")[0] | |
| 48 let xmlenums = xml.findAll("enums") | |
| 49 let commands = xml.findAll("commands")[0] | |
| 50 let features = xml.findAll("feature") # features has extends="<ENUM>" | |
| 51 let extensions = xml.findAll("extensions")[0] # extensions has extends="<ENUM>" | |
| 52 let formats = xml.findAll("formats")[0] | |
| 53 | |
| 54 # gather all enums | |
| 55 | |
| 56 type | |
| 57 EnumEntry = object | |
| 58 name: string | |
| 59 value: string | |
| 60 | |
| 61 EnumDef = object | |
| 62 name: string | |
| 63 values: seq[EnumEntry] | |
| 64 isBitmask: bool | |
| 65 | |
| 66 ConstantDef = object | |
| 67 name: string | |
| 68 datatype: string | |
| 69 value: string | |
| 70 | |
| 71 var consts: seq[ConstantDef] | |
| 72 var enums: Table[string, EnumDef] | |
| 73 | |
| 74 func addValue(edef: var EnumDef, n: XmlNode) = | |
| 75 if n.attr("deprecated") != "aliased" and n.attr("alias") == "": | |
| 76 if n.attr("name") in edef.values.mapIt(it.name): | |
| 77 return | |
| 78 if n.attr("name").endsWith("_EXT") and | |
| 79 n.attr("name")[0 ..< ^4] in edef.values.mapIt(it.name): | |
| 80 return | |
| 81 | |
| 82 var value = "" | |
| 83 if n.attr("value") != "": | |
| 84 value = n.attr("value") | |
| 85 elif n.attr("bitpos") != "": | |
| 86 value = $(1 shl parseInt(n.attr("bitpos"))) | |
| 87 elif n.attr("offset") != "": | |
| 88 var enumBase = 1000000000 | |
| 89 if n.attr("extnumber") != "": | |
| 90 enumBase += (smartParseInt(n.attr("extnumber")) - 1) * 1000 | |
| 91 var v = smartParseInt(n.attr("offset")) + enumBase | |
| 92 if n.attr("dir") == "-": | |
| 93 v = -v | |
| 94 value = $(v) | |
| 95 | |
| 96 edef.values.add EnumEntry(name: n.attr("name"), value: value) | |
| 97 | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
98 func memberDecl(n: XmlNode): string = |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
99 for i in 0 ..< n.len: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
100 if n[i].kind == xnElement and n[i].tag == "comment": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
101 n.delete(i) |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
102 break |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
103 assert n.tag == "member" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
104 debugecho n.toSeq, " ", n.len |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
105 if n.len == 2: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
106 return &"{n[1][0].text}: {n[0][0]}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
107 elif n.len == 3: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
108 if n[1].kind == xnElement and n[1].tag == "name": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
109 return |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
110 &"{n[1][0].text}: array[{n[2].text[1 ..< ^1]}, {TYPEMAP.getOrDefault(n[0][0].text, n[0][0].text)}]]" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
111 else: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
112 assert n[1].text.strip() == "*" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
113 return &"{n[2][0].text}: ptr {n[0][0].text}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
114 elif n.len == 4: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
115 if n[0].text.strip() in ["struct", "const struct"]: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
116 return &"{n[3][0].text}: ptr {n[1][0].text}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
117 else: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
118 assert n[2].text.strip() in ["*", "* const *", "* const*"] |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
119 return &"?" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
120 elif n.len in [5, 6]: |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
121 return &"{n[1][0].text}: array[{n[3][0].text}, {n[0][0].text}]" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
122 assert false |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
123 |
| 1479 | 124 for e in xmlenums: |
| 125 if e.attr("type") == "constants": | |
| 126 for c in e.findAll("enum"): | |
| 127 var value = c.attr("value").strip(chars = {'(', ')'}) | |
| 128 consts.add ConstantDef( | |
| 129 name: c.attr("name"), datatype: TYPEMAP[c.attr("type")], value: value | |
| 130 ) | |
| 131 elif e.attr("type") == "enum": | |
| 132 var edef = EnumDef(name: e.attr("name"), isBitmask: false) | |
| 133 for ee in e.findAll("enum"): | |
| 134 edef.addValue(ee) | |
| 135 enums[edef.name] = edef | |
| 136 elif e.attr("type") == "bitmask": | |
| 137 var edef = EnumDef(name: e.attr("name"), isBitmask: true) | |
| 138 for ee in e.findAll("enum"): | |
| 139 edef.addValue(ee) | |
| 140 enums[edef.name] = edef | |
| 141 | |
| 142 for f in features: | |
| 143 for extendenum in f.findAll("enum"): | |
| 144 if extendenum.attr("extends") != "": | |
| 145 enums[extendenum.attr("extends")].addValue(extendenum) | |
| 146 | |
| 147 for extension in extensions.findAll("extension"): | |
| 148 let extNum = extension.attr("number") | |
| 149 for extendenum in extension.findAll("enum"): | |
| 150 if extendenum.attr("extends") != "": | |
| 151 if extendenum.attr("extnumber") == "": | |
| 152 extendenum.attrs["extnumber"] = extNum | |
| 153 enums[extendenum.attr("extends")].addValue(extendenum) | |
| 154 | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
155 let outPath = (system.currentSourcePath.parentDir() / "api.nim") |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
156 let outFile = open(outPath, fmWrite) |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
157 |
| 1479 | 158 # generate core types =============================================================================== |
| 159 # preamble, much easier to hardcode than to generate from xml | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
160 outFile.writeLine """ |
| 1479 | 161 func VK_MAKE_API_VERSION*( |
| 162 variant: uint32, major: uint32, minor: uint32, patch: uint32 | |
| 163 ): uint32 {.compileTime.} = | |
| 164 (variant shl 29) or (major shl 22) or (minor shl 12) or patch | |
| 165 """ | |
| 166 | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
167 outFile.writeLine "type" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
168 outFile.writeLine """ |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
169 VkSampleMask = distinct uint32 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
170 VkBool32 = distinct uint32 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
171 VkFlags = distinct uint32 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
172 VkFlags64 = distinct uint64 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
173 VkDeviceSize = distinct uint64 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
174 VkDeviceAddress = distinct uint64 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
175 VkRemoteAddressNV = pointer |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
176 """ |
| 1479 | 177 |
| 178 for t in types: | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
179 if t.attr("api") == "vulkansc": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
180 continue |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
181 if t.attr("alias") != "": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
182 continue |
| 1479 | 183 if t.attr("deprecated") == "true": |
| 184 continue | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
185 if t.attr("category") == "include": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
186 continue |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
187 if t.attr("category") == "define": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
188 continue |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
189 if t.attr("category") == "bitmask": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
190 if t.len > 0 and t[0].text.startsWith("typedef"): |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
191 outFile.writeLine &" {t[2][0].text} = distinct {t[1][0].text}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
192 elif t.attr("category") == "union": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
193 let n = t.attr("name") |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
194 outFile.writeLine &" {n}* {{.union.}} = object" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
195 for member in t.findAll("member"): |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
196 outFile.writeLine &" {member.memberDecl()}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
197 elif t.attr("category") == "handle": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
198 outFile.writeLine &" {t[2][0].text} = distinct pointer" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
199 elif t.attr("category") == "struct": |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
200 let n = t.attr("name") |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
201 outFile.writeLine &" {n}* = object" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
202 for member in t.findAll("member"): |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
203 outFile.writeLine &" {member.memberDecl()}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
204 # TODO: funcpointer |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
205 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
206 outFile.writeLine "" |
| 1479 | 207 |
| 208 # generate consts =============================================================================== | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
209 outFile.writeLine "const" |
| 1479 | 210 for c in consts: |
| 211 var value = c.value | |
| 212 if value.endsWith("U"): | |
| 213 value = value[0 ..^ 2] & "'u32" | |
| 214 elif value.endsWith("ULL"): | |
| 215 value = value[0 ..^ 4] & "'u64" | |
| 216 if value[0] == '~': | |
| 217 value = "not " & value[1 ..^ 1] | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
218 outFile.writeLine &" {c.name}*: {c.datatype} = {value}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
219 outFile.writeLine "" |
| 1479 | 220 |
| 221 # generate enums =============================================================================== | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
222 outFile.writeLine "type" |
| 1479 | 223 for edef in enums.values(): |
| 224 if edef.values.len > 0: | |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
225 outFile.writeLine &" {edef.name}* {{.size: 4.}} = enum" |
| 1479 | 226 for ee in edef.values: |
|
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
227 outFile.writeLine &" {ee.name} = {ee.value}" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
228 outFile.writeLine "" |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
229 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
230 outFile.writeLine """ |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
231 when defined(linux): |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
232 include ../semicongine/rendering/vulkan/platform/xlib |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
233 when defined(windows): |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
234 include ../semicongine/rendering/vulkan/platform/win32 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
235 """ |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
236 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
237 outFile.close() |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
238 |
|
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
239 assert execCmd("nim c " & outPath) == 0 |
