Mercurial > games > semicongine
annotate src/vulkan_api/vulkan_api_generator.nim @ 587:713ac2886355
did: small name change
| author | Sam <sam@basx.dev> |
|---|---|
| date | Tue, 11 Apr 2023 01:06:37 +0700 |
| parents | affa6571a2c9 |
| children | 7f921d7d0a2b |
| rev | line source |
|---|---|
| 539 | 1 import std/os |
| 2 import std/sugar | |
| 3 import std/algorithm | |
| 4 import std/strformat | |
| 5 import std/strutils | |
| 6 import std/sequtils | |
| 7 import std/streams | |
| 8 import std/tables | |
| 9 import httpClient | |
| 10 import std/xmlparser | |
| 11 import std/xmltree | |
| 12 | |
| 13 const | |
| 14 TYPEMAP = { | |
| 15 "void": "void", | |
| 16 "char": "char", | |
| 17 "float": "float32", | |
| 18 "double": "float64", | |
| 19 "int8_t": "int8", | |
| 20 "uint8_t": "uint8", | |
| 21 "int16_t": "int16", | |
| 22 "uint16_t": "uint16", | |
| 23 "int32_t": "int32", | |
| 24 "uint32_t": "uint32", | |
| 25 "uint64_t": "uint64", | |
| 26 "int64_t": "int64", | |
| 27 "size_t": "csize_t", | |
| 28 "int": "cint", | |
| 29 "void*": "pointer", | |
| 30 "char*": "cstring", | |
| 31 "ptr char": "cstring", | |
| 32 "ptr void": "pointer", | |
| 33 "VK_DEFINE_HANDLE": "VkHandle", | |
| 34 "VK_DEFINE_NON_DISPATCHABLE_HANDLE": "VkNonDispatchableHandle", | |
| 35 }.toTable | |
| 36 PLATFORM_HEADER_MAP = { | |
| 540 | 37 "X11/Xlib.h": @["xlib", "xlib_xrandr"], |
| 38 "X11/extensions/Xrandr.h": @["xlib_xrandr"], | |
| 39 "wayland-client.h": @["wayland"], | |
| 40 "windows.h": @["win32"], | |
| 41 "xcb/xcb.h": @["xcb"], | |
| 42 "directfb.h": @["directfb"], | |
| 43 "zircon/types.h": @["fuchsia"], | |
| 44 "ggp_c/vulkan_types.h": @["ggp"], | |
| 45 "screen/screen.h": @["screen"], | |
| 46 "nvscisync.h": @["sci"], | |
| 47 "nvscibuf.h": @["sci"], | |
| 48 "vk_video/vulkan_video_codec_h264std.h": @["provisional"], | |
| 49 "vk_video/vulkan_video_codec_h264std_decode.h": @["provisional"], | |
| 50 "vk_video/vulkan_video_codec_h264std_encode.h": @["provisional"], | |
| 51 "vk_video/vulkan_video_codec_h265std.h": @["provisional"], | |
| 52 "vk_video/vulkan_video_codec_h265std_decode.h": @["provisional"], | |
| 53 "vk_video/vulkan_video_codec_h265std_encode.h": @["provisional"], | |
| 539 | 54 }.toTable |
| 55 MAP_KEYWORD = { | |
| 56 "object": "theobject", | |
| 57 "type": "thetype", | |
| 58 }.toTable | |
| 540 | 59 SPECIAL_DEPENDENCIES = { |
| 60 "VK_NV_ray_tracing": "VK_KHR_ray_tracing_pipeline", | |
| 61 }.toTable | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
62 # will be directly loaded at startup |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
63 IGNORED_COMMANDS = @["vkGetInstanceProcAddr"] |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
64 # can be loaded without a vulkan instance |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
65 GLOBAL_COMMANDS = @[ |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
66 "vkEnumerateInstanceVersion", |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
67 "vkEnumerateInstanceExtensionProperties", |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
68 "vkEnumerateInstanceLayerProperties", |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
69 "vkCreateInstance", |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
70 ] |
| 539 | 71 |
| 72 # helpers | |
| 73 func mapType(typename: string): auto = | |
| 74 TYPEMAP.getOrDefault(typename.strip(), typename.strip()).strip(chars={'_'}) | |
| 75 func mapName(thename: string): auto = | |
| 76 MAP_KEYWORD.getOrDefault(thename.strip(), thename.strip()).strip(chars={'_'}) | |
| 77 func smartParseInt(value: string): int = | |
| 78 if value.startsWith("0x"): | |
| 79 parseHexInt(value) | |
| 80 else: | |
| 81 parseInt(value) | |
| 82 func hasAttr(node: XmlNode, attr: string): bool = node.attr(attr) != "" | |
| 83 func tableSorted(table: Table[int, string]): seq[(int, string)] = | |
| 84 result = toSeq(table.pairs) | |
| 85 result.sort((a, b) => cmp(a[0], b[0])) | |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
86 func findType(declNode: XmlNode): string = |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
87 # examples: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
88 # char** -> cstringArray |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
89 # void* -> pointer |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
90 # char* -> cstring |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
91 # |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
92 # int* -> ptr int |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
93 # void** -> ptr pointer |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
94 # int** -> ptr ptr int |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
95 var basetype = "" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
96 var apointer = "" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
97 var arraylen = "" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
98 for child in declNode: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
99 if child.kind == xnText: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
100 if "[" in child.text: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
101 if "[" in child.text and "]" in child.text: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
102 arraylen = child.text.strip(chars={'[', ']'}).replace("][", "*") |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
103 else: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
104 arraylen = declNode.child("enum")[0].text |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
105 else: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
106 for i in 0 ..< child.text.count('*'): |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
107 apointer = apointer & "ptr " |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
108 elif child.tag == "type": |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
109 basetype = mapType(child[0].text) |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
110 if basetype == "void": |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
111 if apointer.count("ptr ") > 0: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
112 basetype = "pointer" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
113 apointer = apointer[0 ..< ^4] |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
114 elif basetype == "char": |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
115 if apointer.count("ptr ") == 1: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
116 basetype = "cstring" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
117 apointer = "" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
118 elif apointer.count("ptr ") == 2: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
119 basetype = "cstringArray" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
120 apointer = "" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
121 elif apointer.count("ptr ") > 2: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
122 basetype = "cstringArray" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
123 apointer = apointer[0 ..< ^8] |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
124 |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
125 result = &"{apointer}{basetype}" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
126 if arraylen != "": |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
127 result = &"array[{arraylen}, {result}]" |
| 539 | 128 |
| 129 # serializers | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
130 # return values and whether this is a bitfield |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
131 func serializeEnum(node: XmlNode, api: XmlNode): (seq[string], string) = |
| 539 | 132 let name = node.attr("name") |
| 133 if name == "": | |
| 134 return result | |
| 135 | |
| 541 | 136 var reservedNames: seq[string] |
| 137 for t in api.findAll("type"): | |
| 138 reservedNames.add t.attr("name").replace("_", "").toLower() | |
| 139 | |
| 539 | 140 # find additional enum defintion in feature definitions |
| 141 var values: Table[int, string] | |
| 541 | 142 for feature in api.findAll("feature"): |
| 539 | 143 for require in feature.findAll("require"): |
| 144 for theenum in require.findAll("enum"): | |
| 145 if theenum.attr("extends") == name: | |
| 146 if theenum.hasAttr("offset"): | |
| 147 let enumBase = 1000000000 + (smartParseInt(theenum.attr("extnumber")) - 1) * 1000 | |
| 148 var value = smartParseInt(theenum.attr("offset")) + enumBase | |
| 149 if theenum.attr("dir") == "-": | |
| 150 value = -value | |
| 151 values[value] = theenum.attr("name") | |
| 152 elif theenum.hasAttr("value"): | |
| 153 var value = smartParseInt(theenum.attr("value")) | |
| 154 if theenum.attr("dir") == "-": | |
| 155 value = -value | |
| 156 values[value] = theenum.attr("name") | |
| 157 elif theenum.hasAttr("bitpos"): | |
| 158 var value = smartParseInt(theenum.attr("bitpos")) | |
| 159 if theenum.attr("dir") == "-": | |
| 160 value = -value | |
| 161 values[value] = theenum.attr("name") | |
| 162 elif theenum.hasAttr("alias"): | |
| 163 discard | |
| 164 else: | |
| 165 raise newException(Exception, &"Unknown extension value: {feature}\nvalue:{theenum}") | |
| 166 # find additional enum defintion in extension definitions | |
| 541 | 167 for extension in api.findAll("extension"): |
| 539 | 168 let extensionNumber = parseInt(extension.attr("number")) |
| 169 let enumBase = 1000000000 + (extensionNumber - 1) * 1000 | |
| 170 for require in extension.findAll("require"): | |
| 171 for theenum in require.findAll("enum"): | |
| 172 if theenum.attr("extends") == name: | |
| 173 if theenum.hasAttr("offset"): | |
| 174 if theenum.hasAttr("extnumber"): | |
| 175 let otherBase = 1000000000 + (smartParseInt(theenum.attr("extnumber")) - 1) * 1000 | |
| 176 var value = smartParseInt(theenum.attr("offset")) + otherBase | |
| 177 if theenum.attr("dir") == "-": | |
| 178 value = -value | |
| 179 values[value] = theenum.attr("name") | |
| 180 else: | |
| 181 var value = smartParseInt(theenum.attr("offset")) + enumBase | |
| 182 if theenum.attr("dir") == "-": | |
| 183 value = -value | |
| 184 values[value] = theenum.attr("name") | |
| 185 elif theenum.hasAttr("value"): | |
| 186 var value = smartParseInt(theenum.attr("value")) | |
| 187 if theenum.attr("dir") == "-": | |
| 188 value = -value | |
| 189 values[value] = theenum.attr("name") | |
| 190 elif theenum.hasAttr("bitpos"): | |
| 191 var value = smartParseInt(theenum.attr("bitpos")) | |
| 192 if theenum.attr("dir") == "-": | |
| 193 value = -value | |
| 194 values[value] = theenum.attr("name") | |
| 195 elif theenum.hasAttr("alias"): | |
| 196 discard | |
| 197 else: | |
| 198 raise newException(Exception, &"Unknown extension value: {extension}\nvalue:{theenum}") | |
| 199 | |
| 200 # generate enums | |
| 201 if node.attr("type") == "enum": | |
| 202 for value in node.findAll("enum"): | |
| 203 if value.hasAttr("alias"): | |
| 204 continue | |
| 205 if value.attr("value").startsWith("0x"): | |
| 206 values[parseHexInt(value.attr("value"))] = value.attr("name") | |
| 207 else: | |
| 208 values[smartParseInt(value.attr("value"))] = value.attr("name") | |
| 209 if values.len > 0: | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
210 result[0].add " " & name & "* {.size: sizeof(cint).} = enum" |
| 539 | 211 for (value, name) in tableSorted(values): |
| 541 | 212 var thename = name |
| 213 if name.replace("_", "").toLower() in reservedNames: | |
| 214 thename = thename & "_ENUM" | |
| 215 let enumEntry = &" {thename} = {value}" | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
216 result[0].add enumEntry |
| 539 | 217 |
| 218 # generate bitsets (normal enums in the C API, but bitfield-enums in Nim) | |
| 219 elif node.attr("type") == "bitmask": | |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
220 var predefined_enum_sets: seq[string] |
| 539 | 221 for value in node.findAll("enum"): |
| 540 | 222 if value.hasAttr("bitpos"): |
| 223 values[smartParseInt(value.attr("bitpos"))] = value.attr("name") | |
| 224 elif node.attr("name") == "VkVideoEncodeRateControlModeFlagBitsKHR": # special exception, for some reason this has values instead of bitpos | |
| 225 values[smartParseInt(value.attr("value"))] = value.attr("name") | |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
226 elif value.hasAttr("value"): # create a const that has multiple bits set |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
227 predefined_enum_sets.add &" {value.attr(\"name\")}* = {value.attr(\"value\")}" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
228 |
| 539 | 229 if values.len > 0: |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
230 let cApiName = name.replace("FlagBits", "Flags") |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
231 result[1] = cApiName |
| 539 | 232 if node.hasAttr("bitwidth"): |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
233 result[0].add " " & name & "* {.size: 8.} = enum" |
| 539 | 234 else: |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
235 result[0].add " " & name & "* {.size: sizeof(cint).} = enum" |
| 539 | 236 for (bitpos, enumvalue) in tableSorted(values): |
| 237 var value = "00000000000000000000000000000000"# makes the bit mask nicely visible | |
| 238 if node.hasAttr("bitwidth"): # assumes this is always 64 | |
| 239 value = value & value | |
| 240 value[^(bitpos + 1)] = '1' | |
| 241 let enumEntry = &" {enumvalue} = 0b{value}" | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
242 if not (enumEntry in result[0]): # the specs define duplicate entries for backwards compat |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
243 result[0].add enumEntry |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
244 if node.hasAttr("bitwidth"): # assuming this attribute is always 64 |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
245 if values.len > 0: |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
246 result[0].add &"""func toBits*(flags: openArray[{name}]): {cApiName} = |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
247 for flag in flags: |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
248 result = {cApiName}(uint64(result) or uint64(flag))""" |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
249 result[0].add &"""func toEnums*(number: {cApiName}): seq[{name}] = |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
250 for value in {name}.items: |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
251 if (cast[uint64](value) and uint64(number)) > 0: |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
252 result.add value""" |
| 555 | 253 result[0].add &"proc `==`*(a, b: {cApiName}): bool = uint64(a) == uint64(b)" |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
254 else: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
255 if values.len > 0: |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
256 result[0].add &"""func toBits*(flags: openArray[{name}]): {cApiName} = |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
257 for flag in flags: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
258 result = {cApiName}(uint(result) or uint(flag))""" |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
259 result[0].add &"""func toEnums*(number: {cApiName}): seq[{name}] = |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
260 for value in {name}.items: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
261 if (value.ord and cint(number)) > 0: |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
262 result.add value""" |
| 555 | 263 result[0].add &"proc `==`*(a, b: {cApiName}): bool = cint(a) == cint(b)" |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
264 if predefined_enum_sets.len > 0: |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
265 result[0].add "const" |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
266 result[0].add predefined_enum_sets |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
267 result[0].add "type" |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
268 |
| 539 | 269 |
| 541 | 270 func serializeStruct(node: XmlNode): seq[string] = |
| 539 | 271 let name = node.attr("name") |
| 272 var union = "" | |
| 273 if node.attr("category") == "union": | |
| 540 | 274 union = "{.union.} " |
| 275 result.add &" {name}* {union}= object" | |
| 539 | 276 for member in node.findAll("member"): |
| 277 if not member.hasAttr("api") or member.attr("api") == "vulkan": | |
| 278 let fieldname = member.child("name")[0].text.strip(chars={'_'}) | |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
279 result.add &" {mapName(fieldname)}*: {findType(member)}" |
| 539 | 280 |
| 281 func serializeFunctiontypes(api: XmlNode): seq[string] = | |
| 282 for node in api.findAll("type"): | |
| 283 if node.attr("category") == "funcpointer": | |
| 284 let name = node[1][0] | |
| 285 let returntype = mapType(node[0].text[8 .. ^1].split('(', 1)[0]) | |
| 286 var params: seq[string] | |
| 287 for i in countup(3, node.len - 1, 2): | |
| 288 var paramname = node[i + 1].text.split(',', 1)[0].split(')', 1)[0] | |
| 289 var paramtype = node[i][0].text | |
| 290 if paramname[0] == '*': | |
| 291 paramname = paramname.rsplit(" ", 1)[1] | |
| 292 paramtype = "ptr " & paramtype | |
| 293 paramname = mapName(paramname) | |
| 294 params.add &"{paramname}: {mapType(paramtype)}" | |
| 295 let paramsstr = params.join(", ") | |
| 540 | 296 result.add(&" {name}* = proc({paramsstr}): {returntype} {{.cdecl.}}") |
| 539 | 297 |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
298 func serializeConsts(api: XmlNode): seq[string] = |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
299 result = @["const"] |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
300 for enums in api.findAll("enums"): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
301 if enums.attr("name") == "API Constants": |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
302 for theenum in enums.findAll("enum"): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
303 if theenum.hasAttr("alias"): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
304 result.add &" {theenum.attr(\"name\")}* = {theenum.attr(\"alias\")}" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
305 else: |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
306 var value = theenum.attr("value").strip(chars={'(', ')'}) |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
307 if value.endsWith("U"): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
308 value = value[0..^2] & "'u32" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
309 elif value.endsWith("ULL"): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
310 value = value[0..^4] & "'u64" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
311 if value[0] == '~': |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
312 value = "not " & value[1..^1] |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
313 result.add &" {theenum.attr(\"name\")}*: {mapType(theenum.attr(\"type\"))} = {value}" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
314 |
| 540 | 315 func serializeType(node: XmlNode, headerTypes: Table[string, string]): Table[string, seq[string]] = |
| 539 | 316 if node.attrsLen == 0: |
| 317 return | |
| 318 if node.attr("requires") == "vk_platform" or node.attr("category") == "include": | |
| 319 return | |
| 320 result["basetypes"] = @[] | |
| 321 result["enums"] = @[] | |
| 322 | |
| 323 # include-defined types (in platform headers) | |
| 540 | 324 if node.attr("name") in headerTypes: |
| 325 for platform in PLATFORM_HEADER_MAP[node.attr("requires")]: | |
| 326 let platformfile = "platform/" & platform | |
| 327 if not result.hasKey(platformfile): | |
| 328 result[platformfile] = @[] | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
329 result[platformfile].add " " & node.attr("name").strip(chars={'_'}) & " *{.header: \"" & node.attr("requires") & "\".} = object" |
| 539 | 330 # generic base types |
| 331 elif node.attr("category") == "basetype": | |
| 332 let typechild = node.child("type") | |
| 333 let namechild = node.child("name") | |
| 334 if typechild != nil and namechild != nil: | |
| 335 var typename = typechild[0].text | |
| 336 if node[2].kind == xnText and node[2].text.strip() == "*": | |
| 337 typename = &"ptr {typename}" | |
| 338 result["basetypes"].add &" {namechild[0].text}* = {mapType(typename)}" | |
| 339 elif namechild != nil: | |
| 340 result["basetypes"].add &" {namechild[0].text}* = object" | |
| 341 # function pointers need to be handled with structs | |
| 342 elif node.attr("category") == "funcpointer": | |
| 343 discard | |
| 344 # preprocessor defines, ignored | |
| 345 elif node.attr("category") == "define": | |
| 346 discard | |
| 347 # bitmask aliases | |
| 348 elif node.attr("category") == "bitmask": | |
| 349 if node.hasAttr("alias"): | |
| 350 let name = node.attr("name") | |
| 351 let alias = node.attr("alias") | |
| 352 result["enums"].add &" {name}* = {alias}" | |
| 353 # distinct resource ID types aka handles | |
| 354 elif node.attr("category") == "handle": | |
| 355 if not node.hasAttr("alias"): | |
| 356 let name = node.child("name")[0].text | |
| 357 var thetype = mapType(node.child("type")[0].text) | |
| 358 result["basetypes"].add &" {name}* = distinct {thetype}" | |
| 359 # enum aliases | |
| 360 elif node.attr("category") == "enum": | |
| 361 if node.hasAttr("alias"): | |
| 362 let name = node.attr("name") | |
| 363 let alias = node.attr("alias") | |
| 364 result["enums"].add &" {name}* = {alias}" | |
| 365 else: | |
| 366 discard | |
| 367 | |
| 540 | 368 func serializeCommand(node: XmlNode): (string, string) = |
| 369 let | |
| 370 proto = node.child("proto") | |
| 371 resulttype = mapType(proto.child("type")[0].text) | |
| 372 name = proto.child("name")[0].text | |
| 373 var params: seq[string] | |
| 374 for param in node: | |
| 375 if param.tag == "param" and param.attr("api") in ["", "vulkan"]: | |
| 376 let fieldname = param.child("name")[0].text.strip(chars={'_'}) | |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
377 params.add &"{mapName(fieldname)}: {findType(param)}" |
| 540 | 378 let allparams = params.join(", ") |
| 379 return (name, &"proc({allparams}): {resulttype} {{.stdcall.}}") | |
| 380 | |
| 539 | 381 |
| 382 proc update(a: var Table[string, seq[string]], b: Table[string, seq[string]]) = | |
| 383 for k, v in b.pairs: | |
| 384 if not a.hasKey(k): | |
| 385 a[k] = @[] | |
| 386 a[k].add v | |
| 387 | |
| 388 | |
| 389 proc main() = | |
| 542 | 390 let file = getTempDir() / "vk.xml" |
| 391 if not os.fileExists(file): | |
| 539 | 392 let client = newHttpClient() |
| 393 let glUrl = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/main/xml/vk.xml" | |
| 542 | 394 client.downloadFile(glUrl, file) |
| 539 | 395 |
| 542 | 396 let api = loadXml(file) |
| 539 | 397 |
| 398 const outdir = "src/vulkan_api/output" | |
| 399 removeDir outdir | |
| 400 createDir outdir | |
| 401 createDir outdir / "platform" | |
| 402 | |
| 403 # index all names that are only available on certain platforms | |
| 404 var platformTypes: Table[string, string] | |
| 405 for extension in api.findAll("extension"): | |
| 406 if extension.hasAttr("platform"): | |
| 407 for thetype in extension.findAll("type"): | |
| 408 platformTypes[thetype.attr("name")] = extension.attr("platform") | |
| 409 for command in extension.findAll("command"): | |
| 410 platformTypes[command.attr("name")] = extension.attr("platform") | |
| 411 elif extension.attr("name").startsWith("VK_KHR_video"): | |
| 412 for thetype in extension.findAll("type"): | |
| 540 | 413 platformTypes[thetype.attr("name")] = "provisional" |
| 539 | 414 for command in extension.findAll("command"): |
| 540 | 415 platformTypes[command.attr("name")] = "provisional" |
| 539 | 416 |
| 417 var outputFiles = { | |
| 540 | 418 "basetypes": @[ |
| 419 "import std/dynlib", | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
420 "import std/tables", |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
421 "import std/strutils", |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
422 "import std/logging", |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
423 "import std/typetraits", |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
424 "import std/macros", |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
425 "import std/private/digitsutils", |
| 540 | 426 "type", |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
427 " VkHandle* = distinct uint", |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
428 " VkNonDispatchableHandle* = distinct uint", |
| 540 | 429 "when defined(linux):", |
| 430 " let vulkanLib* = loadLib(\"libvulkan.so.1\")", | |
| 431 "when defined(windows):", | |
| 432 " let vulkanLib* = loadLib(\"vulkan-1.dll\")", | |
| 433 "if vulkanLib == nil:", | |
| 434 " raise newException(Exception, \"Unable to load vulkan library\")", | |
| 541 | 435 "func VK_MAKE_API_VERSION*(variant: uint32, major: uint32, minor: uint32, patch: uint32): uint32 {.compileTime.} =", |
| 436 " (variant shl 29) or (major shl 22) or (minor shl 12) or patch", | |
| 437 "", | |
| 542 | 438 """template checkVkResult*(call: untyped) = |
| 439 when defined(release): | |
| 440 discard call | |
| 441 else: | |
| 442 # yes, a bit cheap, but this is only for nice debug output | |
| 443 var callstr = astToStr(call).replace("\n", "") | |
| 444 while callstr.find(" ") >= 0: | |
| 445 callstr = callstr.replace(" ", " ") | |
| 446 debug "CALLING vulkan: ", callstr | |
| 447 let value = call | |
| 448 if value != VK_SUCCESS: | |
| 449 error "Vulkan error: ", astToStr(call), " returned ", $value | |
| 450 raise newException(Exception, "Vulkan error: " & astToStr(call) & | |
| 451 " returned " & $value)""", | |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
452 """ |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
453 # custom enum iteration (for enum values > 2^16) |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
454 macro enumFullRange(a: typed): untyped = |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
455 newNimNode(nnkBracket).add(a.getType[1][1..^1]) |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
456 |
|
558
affa6571a2c9
add: swapchain, images, fix some destroctors
Sam <sam@basx.dev>
parents:
555
diff
changeset
|
457 iterator items*[T: HoleyEnum](E: typedesc[T]): T = |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
458 for a in enumFullRange(E): yield a""", |
| 540 | 459 ], |
| 460 "structs": @["type"], | |
| 461 "enums": @["type"], | |
| 462 "commands": @[], | |
| 539 | 463 }.toTable |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
464 outputFiles["basetypes"].add serializeConsts(api) |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
465 outputFiles["basetypes"].add "type" |
| 539 | 466 |
| 467 # enums | |
| 468 for thetype in api.findAll("type"): | |
| 469 if thetype.attr("category") == "bitmask" and not thetype.hasAttr("alias") and (not thetype.hasAttr("api") or thetype.attr("api") == "vulkan"): | |
| 470 let name = thetype.child("name")[0].text | |
| 471 outputFiles["enums"].add &" {name}* = distinct VkFlags" | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
472 |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
473 var bitfields: Table[string, string] |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
474 outputFiles["enums"].add "let vkGetInstanceProcAddr = cast[proc(instance: VkInstance, name: cstring): pointer {.stdcall.}](checkedSymAddr(vulkanLib, \"vkGetInstanceProcAddr\"))" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
475 outputFiles["enums"].add "type" |
| 539 | 476 for theenum in api.findAll("enums"): |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
477 let (enums, bitFieldName) = serializeEnum(theenum, api) |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
478 outputFiles["enums"].add enums |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
479 if bitFieldName != "": |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
480 bitfields[theenum.attr("name")] = bitFieldName |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
481 |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
482 # bitmask-to-string functions |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
483 for thetype in api.findAll("type"): |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
484 if thetype.attr("name") in bitfields: |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
485 let name = bitfields[thetype.attr("name")] |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
486 let stringfunc = &"proc `$`*(bitset: {name}): string = $toEnums(bitset)" |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
487 if not (stringfunc in outputFiles["enums"]): |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
488 outputFiles["enums"].add stringfunc |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
489 outputFiles["enums"].add "type" |
| 539 | 490 |
| 491 # structs and function types need to be in same "type" block to avoid forward-declarations | |
| 492 outputFiles["structs"].add serializeFunctiontypes(api) | |
| 493 for thetype in api.findAll("type"): | |
| 494 if thetype.attr("category") == "struct" or thetype.attr("category") == "union": | |
| 495 var outfile = "structs" | |
| 496 if thetype.attr("name") in platformTypes: | |
| 497 outfile = "platform/" & platformTypes[thetype.attr("name")] | |
| 498 if not (outfile in outputFiles): | |
| 499 outputFiles[outfile] = @[] | |
| 541 | 500 outputFiles[outfile].add serializeStruct(thetype) |
| 539 | 501 |
| 502 # types | |
| 540 | 503 var headerTypes: Table[string, string] |
| 504 for types in api.findAll("types"): | |
| 505 for thetype in types.findAll("type"): | |
| 506 if thetype.attrsLen == 2 and thetype.hasAttr("requires") and thetype.hasAttr("name") and thetype.attr("requires") != "vk_platform": | |
| 507 let name = thetype.attr("name") | |
| 508 let incld = thetype.attr("requires") | |
| 509 headerTypes[name] = &"{name} {{.header: \"{incld}\".}} = object" | |
| 510 | |
| 539 | 511 for typesgroup in api.findAll("types"): |
| 512 for thetype in typesgroup.findAll("type"): | |
| 540 | 513 outputFiles.update serializeType(thetype, headerTypes) |
| 514 | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
515 for typesgroup in api.findAll("types"): |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
516 for node in typesgroup.findAll("type"): |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
517 if node.attr("category") == "handle": |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
518 if not node.hasAttr("alias"): |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
519 let name = node.child("name")[0].text |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
520 outputFiles["basetypes"].add &"proc `$`*(handle: {name}): string = \"{name}(\" & $(uint(handle)) & \")\"" |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
521 outputFiles["basetypes"].add &"proc valid*(handle: {name}): bool = uint(handle) != 0" |
|
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
522 outputFiles["basetypes"].add &"proc reset*(handle: var {name}) = handle = {name}(0)" |
| 555 | 523 outputFiles["basetypes"].add &"proc `==`*(a, b: {name}): bool = uint(a) == uint(b)" |
| 524 | |
|
553
592b28cf65f0
add: more stuff for the vulkan API wrappers
Sam <sam@basx.dev>
parents:
545
diff
changeset
|
525 |
| 540 | 526 # commands aka functions |
| 527 var varDecls: Table[string, string] | |
| 528 var procLoads: Table[string, string] # procloads need to be packed into feature/extension loader procs | |
| 529 for commands in api.findAll("commands"): | |
| 530 for command in commands.findAll("command"): | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
531 if command.attr("api") != "vulkansc" and not (command.attr("name") in IGNORED_COMMANDS): |
| 540 | 532 if command.hasAttr("alias"): |
| 533 let name = command.attr("name") | |
| 534 let alias = command.attr("alias") | |
| 535 let thetype = varDecls[alias].split(":", 1)[1].strip() | |
| 536 varDecls[name] = &" {name}*: {thetype}" | |
| 537 procLoads[name] = &" {name} = {alias}" | |
| 538 else: | |
| 539 let (name, thetype) = serializeCommand(command) | |
| 540 varDecls[name] = &" {name}*: {thetype}" | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
541 procLoads[name] = &" {name} = cast[{thetype}](vkGetInstanceProcAddr(instance, \"{name}\"))" |
| 540 | 542 var declared: seq[string] |
| 543 var featureloads: seq[string] | |
| 544 for feature in api.findAll("feature"): | |
| 545 if feature.attr("api") in ["vulkan", "vulkan,vulkansc"]: | |
| 546 let name = feature.attr("name") | |
| 547 outputFiles["commands"].add &"# feature {name}" | |
| 548 outputFiles["commands"].add "var" | |
| 549 for command in feature.findAll("command"): | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
550 if not (command.attr("name") in declared) and not (command.attr("name") in IGNORED_COMMANDS): |
| 540 | 551 outputFiles["commands"].add varDecls[command.attr("name")] |
| 552 declared.add command.attr("name") | |
| 553 featureloads.add &"load{name}" | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
554 outputFiles["commands"].add &"proc load{name}*(instance: VkInstance) =" |
| 540 | 555 for command in feature.findAll("command"): |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
556 if not (command.attr("name") in IGNORED_COMMANDS & GLOBAL_COMMANDS): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
557 outputFiles["commands"].add procLoads[command.attr("name")] |
| 540 | 558 outputFiles["commands"].add "" |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
559 outputFiles["commands"].add ["proc loadVulkan*(instance: VkInstance) ="] |
| 540 | 560 for l in featureloads: |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
561 outputFiles["commands"].add [&" {l}(instance)"] |
| 540 | 562 outputFiles["commands"].add "" |
| 563 | |
| 564 # for promoted extensions, dependants need to call the load-function of the promoted feature/extension | |
| 565 # use table to store promotions | |
| 566 var promotions: Table[string, string] | |
| 567 for extensions in api.findAll("extensions"): | |
| 568 for extension in extensions.findAll("extension"): | |
| 569 if extension.hasAttr("promotedto"): | |
| 570 promotions[extension.attr("name")] = extension.attr("promotedto") | |
| 571 | |
| 572 var extensionDependencies: Table[string, (seq[string], XmlNode)] | |
| 573 var features: seq[string] | |
| 574 for feature in api.findAll("feature"): | |
| 575 features.add feature.attr("name") | |
| 576 for extensions in api.findAll("extensions"): | |
| 577 for extension in extensions.findAll("extension"): | |
| 578 let name = extension.attr("name") | |
| 579 extensionDependencies[name] = (@[], extension) | |
| 580 if extension.hasAttr("depends"): | |
| 581 extensionDependencies[name] = (extension.attr("depends").split("+"), extension) | |
| 582 if extension.attr("depends").startsWith("("): # no need for full tree parser, only single place where we can use a feature | |
| 583 let dependencies = extension.attr("depends").rsplit({')'}, 1)[1][1 .. ^1].split("+") | |
| 584 extensionDependencies[name] = (dependencies, extension) | |
| 585 if name in SPECIAL_DEPENDENCIES: | |
| 586 extensionDependencies[name][0].add SPECIAL_DEPENDENCIES[name] | |
| 587 | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
588 # order dependencies to generate them in correct order |
| 540 | 589 var dependencyOrderedExtensions: OrderedTable[string, XmlNode] |
| 590 while extensionDependencies.len > 0: | |
| 591 var delkeys: seq[string] | |
| 592 for extensionName, (dependencies, extension) in extensionDependencies.pairs: | |
| 593 var missingExtension = false | |
| 594 for dep in dependencies: | |
| 595 let realdep = promotions.getOrDefault(dep, dep) | |
| 596 if not (realdep in dependencyOrderedExtensions) and not (realdep in features): | |
| 597 missingExtension = true | |
| 598 break | |
| 599 if not missingExtension: | |
| 600 dependencyOrderedExtensions[extensionName] = extension | |
| 601 delkeys.add extensionName | |
| 602 for key in delkeys: | |
| 603 extensionDependencies.del key | |
| 604 | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
605 var extensionLoaderMap: Table[string, Table[string, string]] |
| 540 | 606 for extension in dependencyOrderedExtensions.values: |
| 607 if extension.hasAttr("promotedto"): # will be loaded in promoted place | |
| 608 continue | |
| 609 if extension.attr("supported") in ["", "vulkan", "vulkan,vulkansc"]: | |
| 610 var file = "commands" | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
611 var platform = extension.attr("platform") |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
612 if extension.attr("name").startsWith("VK_KHR_video"): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
613 platform = "provisional" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
614 if platform != "": |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
615 file = "platform/" & platform |
| 540 | 616 let name = extension.attr("name") |
| 617 if extension.findAll("command").len > 0: | |
| 618 outputFiles[file].add &"# extension {name}" | |
| 619 outputFiles[file].add "var" | |
| 620 for command in extension.findAll("command"): | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
621 if not (command.attr("name") in declared) and not (command.attr("name") in IGNORED_COMMANDS): |
| 540 | 622 outputFiles[file].add varDecls[command.attr("name")] |
| 623 declared.add command.attr("name") | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
624 outputFiles[file].add &"proc load{name}*(instance: VkInstance) =" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
625 if not (platform in extensionLoaderMap): |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
626 extensionLoaderMap[platform] = Table[string, string]() |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
627 extensionLoaderMap[platform][name] = &"load{name}" |
| 540 | 628 var addedFunctionBody = false |
| 629 if extension.hasAttr("depends"): | |
| 630 for dependency in extension.attr("depends").split("+"): | |
| 631 # need to check since some extensions have no commands and therefore no load-function | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
632 outputFiles[file].add &" load{promotions.getOrDefault(dependency, dependency)}(instance)" |
| 540 | 633 addedFunctionBody = true |
| 634 for command in extension.findAll("command"): | |
| 635 outputFiles[file].add procLoads[command.attr("name")] | |
| 636 addedFunctionBody = true | |
| 637 if not addedFunctionBody: | |
| 638 outputFiles[file].add " discard" | |
| 639 outputFiles[file].add "" | |
| 640 | |
| 641 var mainout: seq[string] | |
| 642 for section in ["basetypes", "enums", "structs", "commands"]: | |
| 643 mainout.add outputFiles[section] | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
644 mainout.add "var EXTENSION_LOADERS = {" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
645 for extension, loader in extensionLoaderMap[""].pairs: |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
646 mainout.add &" \"{extension}\": {loader}," |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
647 mainout.add "}.toTable" |
| 541 | 648 for platform in api.findAll("platform"): |
| 649 mainout.add &"when defined({platform.attr(\"protect\")}):" | |
| 650 mainout.add &" include platform/{platform.attr(\"name\")}" | |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
651 if platform.attr("name") in extensionLoaderMap: |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
652 for extension, loader in extensionLoaderMap[platform.attr("name")].pairs: |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
653 mainout.add &" EXTENSION_LOADERS[\"{extension}\"] = {loader}" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
654 |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
655 mainout.add "" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
656 mainout.add "proc loadExtension*(instance: VkInstance, extension: string) = EXTENSION_LOADERS[extension](instance)" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
657 mainout.add "" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
658 mainout.add "# load global functions immediately" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
659 mainout.add "block globalFunctions:" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
660 mainout.add " let instance = VkInstance(0)" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
661 for l in GLOBAL_COMMANDS: |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
662 mainout.add procLoads[l] |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
663 mainout.add "" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
664 mainout.add "converter VkBool2NimBool*(a: VkBool32): bool = a > 0" |
|
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
665 mainout.add "converter NimBool2VkBool*(a: bool): VkBool32 = VkBool32(a)" |
|
545
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
666 mainout.add "proc `$`*(x: uint32): string {.raises: [].} = addInt(result, x)" |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
667 |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
668 writeFile outdir / &"api.nim", mainout.join("\n") |
|
39aed3128be7
fix: tons of errors in wrapper generator, can now compile, extension function not loaded yet it seems
Sam <sam@basx.dev>
parents:
544
diff
changeset
|
669 |
|
544
c3c772512e7c
add: new vulkan api wrapper, not done yet
Sam <sam@basx.dev>
parents:
542
diff
changeset
|
670 |
| 539 | 671 for filename, filecontent in outputFiles.pairs: |
| 540 | 672 if filename.startsWith("platform/"): |
| 673 writeFile outdir / &"{filename}.nim", (@[ | |
| 674 "type" | |
| 675 ] & filecontent).join("\n") | |
| 539 | 676 |
| 677 when isMainModule: | |
| 678 main() |
