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"): |