Mercurial > games > semicongine
annotate svk/generate.nim @ 1489:e6bd1f553c1b default tip main
add: quite a bit more wrapper
author | sam <sam@basx.dev> |
---|---|
date | Sun, 18 May 2025 23:47:16 +0700 |
parents | 3ce7c132fdac |
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 }.toTable | |
37 # load xml | |
38 let xml = (system.currentSourcePath.parentDir() / "vk.xml").loadXml() | |
39 let platforms = xml.findAll("platforms")[0] | |
40 let types = xml.findAll("types")[0] | |
41 let xmlenums = xml.findAll("enums") | |
42 let commands = xml.findAll("commands")[0] | |
43 let features = xml.findAll("feature") # features has extends="<ENUM>" | |
44 let extensions = xml.findAll("extensions")[0] # extensions has extends="<ENUM>" | |
45 let formats = xml.findAll("formats")[0] | |
46 | |
47 # gather all enums | |
48 | |
49 type | |
50 EnumEntry = object | |
51 name: string | |
52 value: string | |
53 | |
54 EnumDef = object | |
55 name: string | |
56 values: seq[EnumEntry] | |
57 isBitmask: bool | |
1489 | 58 nBytes: int = 4 |
1479 | 59 |
60 ConstantDef = object | |
61 name: string | |
62 datatype: string | |
63 value: string | |
64 | |
65 var consts: seq[ConstantDef] | |
66 var enums: Table[string, EnumDef] | |
67 | |
68 func addValue(edef: var EnumDef, n: XmlNode) = | |
69 if n.attr("deprecated") != "aliased" and n.attr("alias") == "": | |
70 if n.attr("name") in edef.values.mapIt(it.name): | |
71 return | |
72 | |
73 var value = "" | |
74 if n.attr("value") != "": | |
75 value = n.attr("value") | |
76 elif n.attr("bitpos") != "": | |
77 value = $(1 shl parseInt(n.attr("bitpos"))) | |
78 elif n.attr("offset") != "": | |
79 var enumBase = 1000000000 | |
80 if n.attr("extnumber") != "": | |
81 enumBase += (smartParseInt(n.attr("extnumber")) - 1) * 1000 | |
82 var v = smartParseInt(n.attr("offset")) + enumBase | |
83 if n.attr("dir") == "-": | |
84 v = -v | |
85 value = $(v) | |
86 | |
1482 | 87 if value notin edef.values.mapIt(it.value): |
88 edef.values.add EnumEntry(name: n.attr("name"), value: value) | |
1479 | 89 |
1484 | 90 func doTypename(typename: string, pointerType: int): string = |
91 ## pointerType == 0: no pointer | |
92 ## pointerType == 1: normal pointer (e.g. char *) | |
93 ## pointerType == 2: double pointer (e.g. void **) | |
94 assert pointerType in [0, 1, 2] | |
1481 | 95 result = TYPEMAP.getOrDefault(typename.strip(), typename.strip()).strip(chars = {'_'}) |
96 | |
97 if typename == "void": | |
1484 | 98 assert pointerType > 0 |
1481 | 99 |
1484 | 100 if pointerType > 0: |
1481 | 101 if typename == "void": |
102 result = "pointer" | |
103 elif typename == "char": | |
1485 | 104 if pointerType == 1: |
105 result = "cstring" | |
106 elif pointerType == 2: | |
107 result = "cstringArray" | |
108 else: | |
109 assert false, "Unsupported char pointer type" | |
1481 | 110 else: |
111 result = "ptr " & result | |
1485 | 112 |
113 if pointerType == 2 and typename != "char": | |
1484 | 114 result = "ptr " & result |
1481 | 115 |
116 func doIdentifier(typename: string): string = | |
117 if typename in ["type", "object"]: | |
118 return &"`{typename}`" | |
119 return typename.strip() | |
120 | |
1484 | 121 func doMember(typename, theType: string, pointerType: int, value: string): string = |
1481 | 122 if value == "": |
1484 | 123 &"{doIdentifier(typename)}: {doTypename(theType, pointerType)}" |
1481 | 124 else: |
1484 | 125 &"{doIdentifier(typename)}: {doTypename(theType, pointerType)} = {value}" |
1481 | 126 |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
127 func memberDecl(n: XmlNode): string = |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
128 for i in 0 ..< n.len: |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
129 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
|
130 n.delete(i) |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
131 break |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
132 assert n.tag == "member" |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
133 if n.len == 2: |
1484 | 134 return doMember(n[1][0].text, n[0][0].text, 0, n.attr("values")) |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
135 elif n.len == 3: |
1481 | 136 assert "*" notin n[0][0].text.strip() |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
137 if n[1].kind == xnElement and n[1].tag == "name": |
1481 | 138 # bitfield |
139 if n[2].text.strip().startsWith(":"): | |
140 return | |
1484 | 141 &"{doIdentifier(n[1][0].text)} {{.bitsize:{n[2].text.strip()[1 .. ^1]}.}}: {doTypename(n[0][0].text, 0)}" |
1481 | 142 # array definition |
143 elif n[2].text.strip().startsWith("["): | |
144 let arrayDim = n[2].text[1 ..< ^1] | |
145 if "][" in arrayDim: | |
146 let dims = arrayDim.split("][", 1) | |
147 let (dim1, dim2) = (dims[0], dims[1]) | |
148 return doMember( | |
149 n[1][0].text, | |
1484 | 150 &"array[{dim1}, array[{dim2}, {doTypename(n[0][0].text, 0)}]]", |
151 0, | |
1481 | 152 n.attr("values"), |
153 ) | |
154 else: | |
155 return doMember( | |
156 n[1][0].text, | |
1484 | 157 &"array[{arrayDim}, {doTypename(n[0][0].text, 0)}]", |
158 0, | |
1481 | 159 n.attr("values"), |
160 ) | |
161 else: | |
162 debugecho n.toSeq | |
163 doAssert false, "This should not happen" | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
164 else: |
1481 | 165 # pointer definition |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
166 assert n[1].text.strip() == "*" |
1484 | 167 return doMember(n[2][0].text, n[0][0].text, 1, n.attr("values")) |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
168 elif n.len == 4: |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
169 if n[0].text.strip() in ["struct", "const struct"]: |
1484 | 170 return doMember(n[3][0].text, n[1][0].text, 1, n.attr("values")) |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
171 else: |
1481 | 172 assert n[0].text.strip() == "const" # can be ignored |
173 assert n[1].tag == "type" | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
174 assert n[2].text.strip() in ["*", "* const *", "* const*"] |
1481 | 175 assert n[3].tag == "name" |
176 assert n[1].len == 1 | |
177 assert n[3].len == 1 | |
1485 | 178 return doMember( |
179 n[3][0].text, n[1][0].text, n[2].text.strip().count("*"), n.attr("values") | |
180 ) | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
181 elif n.len in [5, 6]: |
1481 | 182 # array definition, using const-value for array length |
183 # <type>uint8_t</type>,<name>pipelineCacheUUID</name>[<enum>VK_UUID_SIZE</enum>] | |
184 assert n[2].text.strip() == "[" | |
185 assert n[4].text.strip() == "]" | |
186 return doMember( | |
187 n[1][0].text, | |
1484 | 188 &"array[{n[3][0].text}, {doTypename(n[0][0].text, 0)}]", |
189 0, | |
1481 | 190 n.attr("values"), |
191 ) | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
192 assert false |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
193 |
1479 | 194 for e in xmlenums: |
195 if e.attr("type") == "constants": | |
196 for c in e.findAll("enum"): | |
197 var value = c.attr("value").strip(chars = {'(', ')'}) | |
198 consts.add ConstantDef( | |
199 name: c.attr("name"), datatype: TYPEMAP[c.attr("type")], value: value | |
200 ) | |
201 elif e.attr("type") == "enum": | |
202 var edef = EnumDef(name: e.attr("name"), isBitmask: false) | |
203 for ee in e.findAll("enum"): | |
204 edef.addValue(ee) | |
205 enums[edef.name] = edef | |
206 elif e.attr("type") == "bitmask": | |
1489 | 207 let nBytes = if e.attr("bitwidth") == "": 4 else: parseInt(e.attr("bitwidth")) div 8 |
208 var edef = EnumDef(name: e.attr("name"), isBitmask: true, nBytes: nBytes) | |
1479 | 209 for ee in e.findAll("enum"): |
210 edef.addValue(ee) | |
211 enums[edef.name] = edef | |
212 | |
213 for f in features: | |
214 for extendenum in f.findAll("enum"): | |
215 if extendenum.attr("extends") != "": | |
216 enums[extendenum.attr("extends")].addValue(extendenum) | |
217 | |
1486 | 218 var extensionLoaders: seq[(string, seq[string])] |
219 | |
1479 | 220 for extension in extensions.findAll("extension"): |
221 let extNum = extension.attr("number") | |
1486 | 222 extensionLoaders.add (extension.attr("name"), newSeq[string]()) |
223 for c in extension.findAll("command"): | |
224 if "Video" notin c.attr("name"): | |
225 extensionLoaders[^1][1].add c.attr("name") | |
226 | |
1479 | 227 for extendenum in extension.findAll("enum"): |
228 if extendenum.attr("extends") != "": | |
229 if extendenum.attr("extnumber") == "": | |
230 extendenum.attrs["extnumber"] = extNum | |
231 enums[extendenum.attr("extends")].addValue(extendenum) | |
232 | |
1481 | 233 let outPath = (system.currentSourcePath.parentDir() / "vkapi.nim") |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
234 let outFile = open(outPath, fmWrite) |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
235 |
1479 | 236 # generate core types =============================================================================== |
237 # 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
|
238 outFile.writeLine """ |
1481 | 239 |
1484 | 240 import std/dynlib |
1487 | 241 import std/macros |
242 import std/typetraits | |
1484 | 243 |
1481 | 244 import ../semicongine/thirdparty/winim/winim/inc/winbase |
245 import ../semicongine/thirdparty/winim/winim/inc/windef | |
246 import ../semicongine/thirdparty/x11/xlib | |
247 import ../semicongine/thirdparty/x11/x | |
248 import ../semicongine/thirdparty/x11/xrandr | |
249 | |
1479 | 250 func VK_MAKE_API_VERSION*( |
251 variant: uint32, major: uint32, minor: uint32, patch: uint32 | |
1485 | 252 ): uint32 = |
1479 | 253 (variant shl 29) or (major shl 22) or (minor shl 12) or patch |
1487 | 254 |
255 macro enumFullRange(a: typed): untyped = | |
256 newNimNode(nnkBracket).add(a.getType[1][1 ..^ 1]) | |
257 | |
1479 | 258 """ |
259 | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
260 outFile.writeLine "type" |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
261 outFile.writeLine """ |
1487 | 262 |
1481 | 263 # some unused native types |
264 # | |
265 # android | |
266 ANativeWindow = object | |
267 AHardwareBuffer = object | |
268 | |
1483 | 269 # apple/metal |
1481 | 270 CAMetalLayer = object |
271 MTLSharedEvent_id = object | |
1483 | 272 MTLDevice_id = object |
273 MTLCommandQueue_id = object | |
274 MTLBuffer_id = object | |
275 MTLTexture_id = object | |
276 IOSurfaceRef = object | |
1481 | 277 |
278 # wayland | |
279 wl_display = object | |
280 wl_surface = object | |
281 | |
282 # XCB | |
283 xcb_connection_t = object | |
284 xcb_window_t = object | |
285 xcb_visualid_t = object | |
286 | |
287 # directfb | |
288 IDirectFB = object | |
289 IDirectFBSurface = object | |
290 | |
291 # Zircon | |
292 zx_handle_t = object | |
293 | |
294 # GGP C | |
295 GgpStreamDescriptor = object | |
296 GgpFrameToken = object | |
297 | |
298 # Screen (nintendo switch?) | |
299 screen_context = object | |
300 screen_window = object | |
301 screen_buffer = object | |
302 | |
303 # Nvidia | |
304 NvSciSyncAttrList = object | |
305 NvSciSyncObj = object | |
306 NvSciSyncFence = object | |
307 NvSciBufAttrList = object | |
308 NvSciBufObj = object | |
309 | |
310 # some base vulkan base types | |
1483 | 311 VkSampleMask* = distinct uint32 |
312 VkBool32* = distinct uint32 | |
313 VkFlags* = distinct uint32 | |
314 VkFlags64* = distinct uint64 | |
315 VkDeviceSize* = distinct uint64 | |
316 VkDeviceAddress* = distinct uint64 | |
317 VkRemoteAddressNV* = pointer | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
318 """ |
1479 | 319 |
320 # generate consts =============================================================================== | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
321 outFile.writeLine "const" |
1479 | 322 for c in consts: |
323 var value = c.value | |
324 if value.endsWith("U"): | |
325 value = value[0 ..^ 2] & "'u32" | |
326 elif value.endsWith("ULL"): | |
327 value = value[0 ..^ 4] & "'u64" | |
328 if value[0] == '~': | |
329 value = "not " & value[1 ..^ 1] | |
1486 | 330 if c.name in ["VK_TRUE", "VK_FALSE"]: |
331 outFile.writeLine &" {c.name}*: VkBool32 = VkBool32({value})" | |
332 else: | |
333 outFile.writeLine &" {c.name}*: {c.datatype} = {value}" | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
334 outFile.writeLine "" |
1479 | 335 |
336 # generate enums =============================================================================== | |
1481 | 337 const nameCollisions = [ |
338 "VK_PIPELINE_CACHE_HEADER_VERSION_ONE", | |
339 "VK_PIPELINE_CACHE_HEADER_VERSION_SAFETY_CRITICAL_ONE", | |
340 "VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT", | |
341 ] | |
1482 | 342 |
1479 | 343 for edef in enums.values(): |
344 if edef.values.len > 0: | |
1489 | 345 outFile.writeLine &"type {edef.name}* {{.size: {edef.nBytes}.}} = enum" |
1479 | 346 for ee in edef.values: |
1481 | 347 # due to the nim identifier-system, there might be collisions between typenames and enum-member names |
348 if ee.name in nameCollisions: | |
1487 | 349 outFile.writeLine &" {ee.name}_VALUE = {ee.value}" |
1481 | 350 else: |
1487 | 351 outFile.writeLine &" {ee.name} = {ee.value}" |
1481 | 352 |
1487 | 353 outFile.writeLine "type" |
1481 | 354 |
355 # generate types =============================================================================== | |
1486 | 356 var stringConverters: seq[string] |
1481 | 357 for t in types: |
358 let category = t.attr("category") | |
1483 | 359 let tName = t.attr("name") |
360 if tName.startsWith("VkVideo"): # we are not doing the video API, sorry | |
361 continue | |
362 if tName.startsWith("VkPhysicalDeviceVideo"): # we are not doing the video API, sorry | |
363 continue | |
1481 | 364 if t.attr("api") == "vulkansc": |
365 continue | |
366 elif t.attr("deprecated") == "true": | |
367 continue | |
368 elif category == "include": | |
369 continue | |
370 elif category == "define": | |
371 continue | |
372 elif t.attr("requires").startsWith("vk_video"): | |
373 continue | |
374 elif t.attr("alias") != "": | |
375 let a = t.attr("alias") | |
1483 | 376 outFile.writeLine &" {tName}* = {a}" |
1481 | 377 elif category == "bitmask": |
378 if t.len > 0 and t[0].text.startsWith("typedef"): | |
1486 | 379 outFile.writeLine &" {t[2][0].text.strip()}* = distinct {t[1][0].text.strip()}" |
1481 | 380 elif category == "union": |
1483 | 381 outFile.writeLine &" {tName}* {{.union.}} = object" |
1481 | 382 for member in t.findAll("member"): |
383 outFile.writeLine &" {member.memberDecl()}" | |
384 elif category == "handle": | |
1486 | 385 outFile.writeLine &" {t[2][0].text.strip()} = distinct pointer" |
386 stringConverters.add t[2][0].text.strip() | |
1481 | 387 elif category == "struct": |
1483 | 388 outFile.writeLine &" {tName}* = object" |
1481 | 389 for member in t.findAll("member"): |
390 if member.attr("api") == "vulkansc": | |
391 continue | |
392 outFile.writeLine &" {member.memberDecl()}" | |
393 elif category == "funcpointer": | |
394 assert t[0].text.startsWith("typedef ") | |
1483 | 395 let retName = t[0].text[8 ..< ^13].strip() |
396 let funcName = t.findAll("name")[0][0].text | |
397 | |
398 outFile.write &" {funcname}* = proc(" | |
1484 | 399 let nParams = (t.len - 3) div 2 |
400 for i in 0 ..< nParams: | |
401 assert t[i * 2 + 3].tag == "type" | |
402 let typename = t[i * 2 + 3][0].text.strip() | |
403 var identifier = t[i * 2 + 4].text.strip(chars = {' ', ')', ';', ',', '\n'}) | |
404 var pointerType = if identifier.startsWith("*"): 1 else: 0 | |
405 if pointerType > 0: | |
406 identifier = identifier[1 .. ^1].strip(chars = {' ', ')', ';', ',', '\n'}) | |
407 if identifier.endsWith("const"): | |
408 identifier = identifier[0 .. ^6].strip(chars = {' ', ')', ';', ',', '\n'}) | |
409 identifier = identifier.strip(chars = {','}) | |
410 outFile.write &"{doIdentifier(identifier)}: {doTypename(typename, pointerType)}, " | |
1483 | 411 |
1484 | 412 if retName == "void": |
1483 | 413 outFile.writeLine &") {{.cdecl.}}" |
1484 | 414 elif retName == "void*": |
1483 | 415 outFile.writeLine &"): pointer {{.cdecl.}}" |
416 else: | |
1484 | 417 outFile.writeLine &"): {doTypename(retName, 0)} {{.cdecl.}}" |
1481 | 418 else: |
419 doAssert category in ["", "basetype", "enum"], "unknown type category: " & category | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
420 outFile.writeLine "" |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
421 |
1487 | 422 for edef in enums.values(): |
423 if edef.values.len > 0: | |
424 if edef.isBitmask: | |
1489 | 425 let enumName = edef.name |
426 let p = enumName.rfind("FlagBits") | |
427 let flagSetType = enumName[0 ..< p] & "Flags" & enumName[p + 8 .. ^1] | |
1487 | 428 |
1489 | 429 outFile.writeLine &""" |
430 func `or`(a: {flagSetType}, b: {enumName}): {flagSetType} {{.hint[XDeclaredButNotUsed]: off.}} = | |
431 {flagSetType}(distinctBase({flagSetType})(a) or distinctBase({flagSetType})(b)) | |
432 func `or`(a, b: {enumName}): {flagSetType} {{.hint[XDeclaredButNotUsed]: off.}} = | |
433 {flagSetType}(distinctBase({flagSetType})(a) or distinctBase({flagSetType})(b)) | |
434 func contains(flags: {flagSetType}, flag: {enumName}): bool {{.hint[XDeclaredButNotUsed]: off.}} = | |
435 (distinctBase({flagSetType})(flags) and distinctBase({flagSetType})(flag)) > 0 | |
436 """ | |
437 outFile.writeLine &"func `$`*(bits: {flagSetType}): string =" | |
438 outFile.writeLine &""" | |
439 for value in enumFullRange({enumName}): | |
440 if (value.ord and cint(bits)) > 0: | |
441 result &= $value & "|" | |
442 result.setLen(max(0, result.len - 1)) | |
443 """ | |
1487 | 444 outFile.writeLine "" |
445 | |
1483 | 446 for command in commands: |
447 if command.attr("api") == "vulkansc": | |
448 continue | |
449 if command.attr("alias") != "": | |
450 let funcName = command.attr("name") | |
451 let funcAlias = command.attr("alias") | |
1485 | 452 outFile.write &"var {funcName}* = {funcAlias}\n" |
1483 | 453 continue |
454 | |
455 let proto = command.findAll("proto")[0] | |
456 let retType = proto.findAll("type")[0][0].text.strip() | |
457 let funcName = proto.findAll("name")[0][0].text.strip() | |
458 | |
459 if "Video" in funcName: # Video API not supported at this time | |
460 continue | |
461 | |
1485 | 462 outFile.write &"var {funcName}*: proc(" |
1483 | 463 for param in command: |
464 if param.tag != "param": | |
465 continue | |
466 if param.attr("api") == "vulkansc": | |
467 continue | |
468 assert param.len in [2, 3, 4] | |
469 let paramType = param.findAll("type")[0][0].text | |
470 let paramName = param.findAll("name")[0][0].text | |
471 assert "*" notin paramType, $param | |
1484 | 472 |
473 if param.len == 4: | |
474 param.delete(0) | |
475 | |
476 var pointerType = 0 | |
477 | |
478 if param.len == 3: | |
479 if param[param.len - 1].kind == xnText: | |
480 assert param[param.len - 1].text[^1] == ']' | |
481 else: | |
482 assert param[0].tag == "type" | |
483 assert param[param.len - 1].tag == "name" | |
484 if param[1].text.strip() == "*": | |
485 pointerType = 1 | |
486 elif param[1].text.strip() == "**": | |
487 pointerType = 2 | |
488 # echo "3: ", param[1].text, " ", paramType, " ", paramName | |
489 outFile.write &"{doIdentifier(paramName)}: {doTypename(paramType, pointerType)}, " | |
1483 | 490 |
491 outFile.write &")" | |
492 if retType != "void": | |
493 assert "*" notin retType | |
1484 | 494 outFile.write &": {doTypename(retType, 0)}" |
1483 | 495 outFile.write " {.stdcall.}\n" |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
496 |
1484 | 497 outFile.write """ |
1485 | 498 |
499 proc loadFunc[T](instance: VkInstance, f: var T, name: string) = | |
500 f = cast[T](vkGetInstanceProcAddr(instance, name)) | |
501 | |
1486 | 502 proc initVulkanLoader*() = |
503 if vkGetInstanceProcAddr != nil: | |
504 return | |
505 | |
506 when defined(linux): | |
507 let vulkanLib = loadLib("libvulkan.so.1") | |
508 when defined(windows): | |
509 let vulkanLib = loadLib("vulkan-1.dll") | |
510 if vulkanLib == nil: | |
511 raise newException(Exception, "Unable to load vulkan library") | |
512 | |
513 # init two global functions | |
514 vkGetInstanceProcAddr = cast[proc(instance: VkInstance, pName: cstring, ): PFN_vkVoidFunction {.stdcall.}](checkedSymAddr(vulkanLib, "vkGetInstanceProcAddr")) | |
515 | |
516 loadFunc(VkInstance(nil), vkCreateInstance, "vkCreateInstance") | |
517 | |
1485 | 518 """ |
519 | |
520 for f in features: | |
521 let name = f.attr("name").replace(",", "_") | |
522 if f.attr("struct") != "": | |
523 continue | |
1486 | 524 outFile.writeLine &"proc load_{name}(instance: VkInstance) =" |
1485 | 525 var hasEntries = false |
526 for cmd in f.findAll("command"): | |
1486 | 527 if cmd.attr("name") == "vkCreateInstance": |
528 continue | |
1485 | 529 hasEntries = true |
530 let cName = cmd.attr("name") | |
531 outFile.writeLine &" loadFunc(instance, {cName}, \"{cName}\")" | |
532 if not hasEntries: | |
533 outFile.writeLine " discard" | |
534 outFile.writeLine "" | |
1484 | 535 |
1486 | 536 for (extName, commands) in extensionLoaders: |
537 outFile.writeLine &"proc load_{extName}(instance: VkInstance) =" | |
538 for c in commands: | |
539 outFile.writeLine &" loadFunc(instance, {c}, \"{c}\")" | |
540 if commands.len == 0: | |
541 outFile.writeLine &" discard" | |
542 outFile.writeLine "" | |
543 | |
544 outFile.writeLine "const EXTENSION_LOADERS = {" | |
545 for (extName, commands) in extensionLoaders: | |
546 outFile.writeLine &" \"{extName}\": load_{extName}," | |
547 outFile.writeLine "}.toTable" | |
548 outFile.writeLine "" | |
549 | |
550 outFile.writeLine "proc loadExtension*(instance: VkInstance, name: string) =" | |
551 outFile.writeLine " assert name in EXTENSION_LOADERS" | |
552 outFile.writeLine " EXTENSION_LOADERS[name](instance)" | |
553 outFile.writeLine "" | |
554 | |
555 for strCon in stringConverters: | |
556 outFile.writeLine &"""proc `$`*(v: {strCon}): string = "0x" & cast[uint](v).toHex()""" | |
557 outFile.writeLine "" | |
558 | |
559 outFile.writeLine "" | |
560 | |
1480
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
561 outFile.close() |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
562 |
0b302531f5c5
did: continue on vulkan nim api generator
sam <sam@basx.dev>
parents:
1479
diff
changeset
|
563 assert execCmd("nim c " & outPath) == 0 |