Mercurial > games > semicongine
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"): | 
