comparison src/vulkan_api/vulkan_api_generator.nim @ 92:e872cf354110

add: more stuff for the vulkan API wrappers
author Sam <sam@basx.dev>
date Tue, 28 Feb 2023 00:08:28 +0700
parents 8412f433dc46
children f036546f5ea2
comparison
equal deleted inserted replaced
91:2e9823f9193f 92:e872cf354110
125 result = &"{apointer}{basetype}" 125 result = &"{apointer}{basetype}"
126 if arraylen != "": 126 if arraylen != "":
127 result = &"array[{arraylen}, {result}]" 127 result = &"array[{arraylen}, {result}]"
128 128
129 # serializers 129 # serializers
130 func serializeEnum(node: XmlNode, api: XmlNode): seq[string] = 130 # return values and whether this is a bitfield
131 func serializeEnum(node: XmlNode, api: XmlNode): (seq[string], string) =
131 let name = node.attr("name") 132 let name = node.attr("name")
132 if name == "": 133 if name == "":
133 return result 134 return result
134 135
135 var reservedNames: seq[string] 136 var reservedNames: seq[string]
204 if value.attr("value").startsWith("0x"): 205 if value.attr("value").startsWith("0x"):
205 values[parseHexInt(value.attr("value"))] = value.attr("name") 206 values[parseHexInt(value.attr("value"))] = value.attr("name")
206 else: 207 else:
207 values[smartParseInt(value.attr("value"))] = value.attr("name") 208 values[smartParseInt(value.attr("value"))] = value.attr("name")
208 if values.len > 0: 209 if values.len > 0:
209 result.add " " & name & "* {.size: sizeof(cint).} = enum" 210 result[0].add " " & name & "* {.size: sizeof(cint).} = enum"
210 for (value, name) in tableSorted(values): 211 for (value, name) in tableSorted(values):
211 var thename = name 212 var thename = name
212 if name.replace("_", "").toLower() in reservedNames: 213 if name.replace("_", "").toLower() in reservedNames:
213 thename = thename & "_ENUM" 214 thename = thename & "_ENUM"
214 let enumEntry = &" {thename} = {value}" 215 let enumEntry = &" {thename} = {value}"
215 result.add enumEntry 216 result[0].add enumEntry
216 217
217 # generate bitsets (normal enums in the C API, but bitfield-enums in Nim) 218 # generate bitsets (normal enums in the C API, but bitfield-enums in Nim)
218 elif node.attr("type") == "bitmask": 219 elif node.attr("type") == "bitmask":
219 var predefined_enum_sets: seq[string] 220 var predefined_enum_sets: seq[string]
220 for value in node.findAll("enum"): 221 for value in node.findAll("enum"):
224 values[smartParseInt(value.attr("value"))] = value.attr("name") 225 values[smartParseInt(value.attr("value"))] = value.attr("name")
225 elif value.hasAttr("value"): # create a const that has multiple bits set 226 elif value.hasAttr("value"): # create a const that has multiple bits set
226 predefined_enum_sets.add &" {value.attr(\"name\")}* = {value.attr(\"value\")}" 227 predefined_enum_sets.add &" {value.attr(\"name\")}* = {value.attr(\"value\")}"
227 228
228 if values.len > 0: 229 if values.len > 0:
230 let cApiName = name.replace("FlagBits", "Flags")
231 result[1] = cApiName
229 if node.hasAttr("bitwidth"): 232 if node.hasAttr("bitwidth"):
230 result.add " " & name & "* {.size: 8.} = enum" 233 result[0].add " " & name & "* {.size: 8.} = enum"
231 else: 234 else:
232 result.add " " & name & "* {.size: sizeof(cint).} = enum" 235 result[0].add " " & name & "* {.size: sizeof(cint).} = enum"
233 for (bitpos, enumvalue) in tableSorted(values): 236 for (bitpos, enumvalue) in tableSorted(values):
234 var value = "00000000000000000000000000000000"# makes the bit mask nicely visible 237 var value = "00000000000000000000000000000000"# makes the bit mask nicely visible
235 if node.hasAttr("bitwidth"): # assumes this is always 64 238 if node.hasAttr("bitwidth"): # assumes this is always 64
236 value = value & value 239 value = value & value
237 value[^(bitpos + 1)] = '1' 240 value[^(bitpos + 1)] = '1'
238 let enumEntry = &" {enumvalue} = 0b{value}" 241 let enumEntry = &" {enumvalue} = 0b{value}"
239 if not (enumEntry in result): # the specs define duplicate entries for backwards compat 242 if not (enumEntry in result[0]): # the specs define duplicate entries for backwards compat
240 result.add enumEntry 243 result[0].add enumEntry
241 let cApiName = name.replace("FlagBits", "Flags")
242 if node.hasAttr("bitwidth"): # assuming this attribute is always 64 244 if node.hasAttr("bitwidth"): # assuming this attribute is always 64
243 if values.len > 0: 245 if values.len > 0:
244 result.add &"""converter BitsetToNumber*(flags: openArray[{name}]): {cApiName} = 246 result[0].add &"""func toBits*(flags: openArray[{name}]): {cApiName} =
245 for flag in flags: 247 for flag in flags:
246 result = {cApiName}(int64(result) or int64(flag))""" 248 result = {cApiName}(uint64(result) or uint64(flag))"""
247 result.add &"""converter NumberToBitset*(number: {cApiName}): seq[{name}] = 249 result[0].add &"""func toEnums*(number: {cApiName}): seq[{name}] =
248 for value in {name}.items: 250 for value in {name}.items:
249 if (value.ord and int64(number)) > 0: 251 if (cast[uint64](value) and uint64(number)) > 0:
250 result.add value""" 252 result.add value"""
251 else: 253 else:
252 if values.len > 0: 254 if values.len > 0:
253 result.add &"""func toBits*(flags: openArray[{name}]): {cApiName} = 255 result[0].add &"""func toBits*(flags: openArray[{name}]): {cApiName} =
254 for flag in flags: 256 for flag in flags:
255 result = {cApiName}(uint(result) or uint(flag))""" 257 result = {cApiName}(uint(result) or uint(flag))"""
256 result.add &"""func toEnums*(number: {cApiName}): seq[{name}] = 258 result[0].add &"""func toEnums*(number: {cApiName}): seq[{name}] =
257 for value in {name}.items: 259 for value in {name}.items:
258 if (value.ord and cint(number)) > 0: 260 if (value.ord and cint(number)) > 0:
259 result.add value""" 261 result.add value"""
260 if predefined_enum_sets.len > 0: 262 if predefined_enum_sets.len > 0:
261 result.add "const" 263 result[0].add "const"
262 result.add predefined_enum_sets 264 result[0].add predefined_enum_sets
263 result.add "type" 265 result[0].add "type"
264 266
265 267
266 func serializeStruct(node: XmlNode): seq[string] = 268 func serializeStruct(node: XmlNode): seq[string] =
267 let name = node.attr("name") 269 let name = node.attr("name")
268 var union = "" 270 var union = ""
414 "basetypes": @[ 416 "basetypes": @[
415 "import std/dynlib", 417 "import std/dynlib",
416 "import std/tables", 418 "import std/tables",
417 "import std/strutils", 419 "import std/strutils",
418 "import std/logging", 420 "import std/logging",
421 "import std/typetraits",
419 "import std/macros", 422 "import std/macros",
420 "import std/private/digitsutils", 423 "import std/private/digitsutils",
421 "from typetraits import HoleyEnum", 424 "from typetraits import HoleyEnum",
422 "type", 425 "type",
423 " VkHandle* = distinct uint", 426 " VkHandle* = distinct uint",
463 # enums 466 # enums
464 for thetype in api.findAll("type"): 467 for thetype in api.findAll("type"):
465 if thetype.attr("category") == "bitmask" and not thetype.hasAttr("alias") and (not thetype.hasAttr("api") or thetype.attr("api") == "vulkan"): 468 if thetype.attr("category") == "bitmask" and not thetype.hasAttr("alias") and (not thetype.hasAttr("api") or thetype.attr("api") == "vulkan"):
466 let name = thetype.child("name")[0].text 469 let name = thetype.child("name")[0].text
467 outputFiles["enums"].add &" {name}* = distinct VkFlags" 470 outputFiles["enums"].add &" {name}* = distinct VkFlags"
471
472 var bitfields: Table[string, string]
468 outputFiles["enums"].add "let vkGetInstanceProcAddr = cast[proc(instance: VkInstance, name: cstring): pointer {.stdcall.}](checkedSymAddr(vulkanLib, \"vkGetInstanceProcAddr\"))" 473 outputFiles["enums"].add "let vkGetInstanceProcAddr = cast[proc(instance: VkInstance, name: cstring): pointer {.stdcall.}](checkedSymAddr(vulkanLib, \"vkGetInstanceProcAddr\"))"
469 outputFiles["enums"].add "type" 474 outputFiles["enums"].add "type"
470 for theenum in api.findAll("enums"): 475 for theenum in api.findAll("enums"):
471 outputFiles["enums"].add serializeEnum(theenum, api) 476 let (enums, bitFieldName) = serializeEnum(theenum, api)
477 outputFiles["enums"].add enums
478 if bitFieldName != "":
479 bitfields[theenum.attr("name")] = bitFieldName
480
481 # bitmask-to-string functions
482 for thetype in api.findAll("type"):
483 if thetype.attr("name") in bitfields:
484 let name = bitfields[thetype.attr("name")]
485 let stringfunc = &"proc `$`*(bitset: {name}): string = $toEnums(bitset)"
486 if not (stringfunc in outputFiles["enums"]):
487 outputFiles["enums"].add stringfunc
488 outputFiles["enums"].add "type"
472 489
473 # structs and function types need to be in same "type" block to avoid forward-declarations 490 # structs and function types need to be in same "type" block to avoid forward-declarations
474 outputFiles["structs"].add serializeFunctiontypes(api) 491 outputFiles["structs"].add serializeFunctiontypes(api)
475 for thetype in api.findAll("type"): 492 for thetype in api.findAll("type"):
476 if thetype.attr("category") == "struct" or thetype.attr("category") == "union": 493 if thetype.attr("category") == "struct" or thetype.attr("category") == "union":
491 headerTypes[name] = &"{name} {{.header: \"{incld}\".}} = object" 508 headerTypes[name] = &"{name} {{.header: \"{incld}\".}} = object"
492 509
493 for typesgroup in api.findAll("types"): 510 for typesgroup in api.findAll("types"):
494 for thetype in typesgroup.findAll("type"): 511 for thetype in typesgroup.findAll("type"):
495 outputFiles.update serializeType(thetype, headerTypes) 512 outputFiles.update serializeType(thetype, headerTypes)
513
514 for typesgroup in api.findAll("types"):
515 for node in typesgroup.findAll("type"):
516 if node.attr("category") == "handle":
517 if not node.hasAttr("alias"):
518 let name = node.child("name")[0].text
519 outputFiles["basetypes"].add &"proc `$`*(handle: {name}): string = \"{name}(\" & $(uint(handle)) & \")\""
520 outputFiles["basetypes"].add &"proc valid*(handle: {name}): bool = uint(handle) != 0"
521 outputFiles["basetypes"].add &"proc reset*(handle: var {name}) = handle = {name}(0)"
496 522
497 # commands aka functions 523 # commands aka functions
498 var varDecls: Table[string, string] 524 var varDecls: Table[string, string]
499 var procLoads: Table[string, string] # procloads need to be packed into feature/extension loader procs 525 var procLoads: Table[string, string] # procloads need to be packed into feature/extension loader procs
500 for commands in api.findAll("commands"): 526 for commands in api.findAll("commands"):