Mercurial > games > semicongine
annotate svk/generate.nim @ 1480:0b302531f5c5 default tip
did: continue on vulkan nim api generator
author | sam <sam@basx.dev> |
---|---|
date | Mon, 21 Apr 2025 01:31:55 +0700 |
parents | 172ac338f820 |
children |
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 |