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