create_vulkan_odin_wrapper.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. import re
  2. import urllib.request as req
  3. from tokenize import tokenize
  4. from io import BytesIO
  5. import string
  6. import os.path
  7. import math
  8. file_and_urls = [
  9. ("vk_platform.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_platform.h', True),
  10. ("vulkan_core.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_core.h', False),
  11. ("vk_layer.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_layer.h', True),
  12. ("vk_icd.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_icd.h', True),
  13. ("vulkan_win32.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_win32.h', False),
  14. ("vulkan_metal.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_metal.h', False),
  15. ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False),
  16. ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False),
  17. ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False),
  18. # Vulkan Video
  19. ("vulkan_video_codec_h264std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h264std.h', False),
  20. ("vulkan_video_codec_h265std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h265std.h', False),
  21. ("vulkan_video_codec_h264std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h264std_decode.h', False),
  22. ("vulkan_video_codec_h265std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h265std_decode.h', False),
  23. ]
  24. for file, url, _ in file_and_urls:
  25. if not os.path.isfile(file):
  26. with open(file, 'w', encoding='utf-8') as f:
  27. f.write(req.urlopen(url).read().decode('utf-8'))
  28. src = ""
  29. for file, _, skip in file_and_urls:
  30. if skip: continue
  31. with open(file, 'r', encoding='utf-8') as f:
  32. src += f.read()
  33. def no_vk(t):
  34. t = t.replace('Vk', '')
  35. t = t.replace('PFN_vk_icd', 'Procicd')
  36. t = t.replace('PFN_vk', 'Proc')
  37. t = t.replace('PFN_', 'Proc')
  38. t = t.replace('PFN_', 'Proc')
  39. t = t.replace('VK_', '')
  40. # Vulkan Video
  41. t = t.replace('STD_', '')
  42. t = t.replace('Std', '')
  43. return t
  44. OPAQUE_STRUCTS = """
  45. wl_surface :: struct {} // Opaque struct defined by Wayland
  46. wl_display :: struct {} // Opaque struct defined by Wayland
  47. IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework
  48. """
  49. def convert_type(t, prev_name, curr_name):
  50. table = {
  51. "Bool32": 'b32',
  52. "float": 'f32',
  53. "double": 'f64',
  54. "uint32_t": 'u32',
  55. "uint64_t": 'u64',
  56. "size_t": 'int',
  57. 'int32_t': 'i32',
  58. 'int64_t': 'i64',
  59. 'int': 'c.int',
  60. 'uint8_t': 'u8',
  61. 'int8_t': 'i8',
  62. "uint16_t": 'u16',
  63. "char": "byte",
  64. "void": "void",
  65. "void*": "rawptr",
  66. "void *": "rawptr",
  67. "char*": 'cstring',
  68. "const uint32_t* const*": "^[^]u32",
  69. "const void*": 'rawptr',
  70. "const char*": 'cstring',
  71. "const char* const*": '[^]cstring',
  72. "const ObjectTableEntryNVX* const*": "^^ObjectTableEntryNVX",
  73. "const void* const *": "[^]rawptr",
  74. "const AccelerationStructureGeometryKHR* const*": "^[^]AccelerationStructureGeometryKHR",
  75. "const AccelerationStructureBuildRangeInfoKHR* const*": "^[^]AccelerationStructureBuildRangeInfoKHR",
  76. "const MicromapUsageEXT* const*": "^[^]MicromapUsageEXT",
  77. "struct BaseOutStructure": "BaseOutStructure",
  78. "struct BaseInStructure": "BaseInStructure",
  79. "struct wl_display": "wl_display",
  80. "struct wl_surface": "wl_surface",
  81. 'v': '',
  82. }
  83. if t in table.keys():
  84. return table[t]
  85. if t == "":
  86. return t
  87. elif t.endswith("*"):
  88. elem = ""
  89. pointer = "^"
  90. if t.startswith("const"):
  91. ttype = t[6:len(t)-1]
  92. elem = convert_type(ttype, prev_name, curr_name)
  93. else:
  94. ttype = t[:len(t)-1]
  95. elem = convert_type(ttype, prev_name, curr_name)
  96. if curr_name.endswith("s") or curr_name.endswith("Table"):
  97. if prev_name.endswith("Count") or prev_name.endswith("Counts"):
  98. pointer = "[^]"
  99. elif curr_name.startswith("pp"):
  100. if elem.startswith("[^]"):
  101. pass
  102. else:
  103. pointer = "[^]"
  104. elif curr_name.startswith("p"):
  105. pointer = "[^]"
  106. if curr_name and elem.endswith("Flags"):
  107. pointer = "[^]"
  108. return "{}{}".format(pointer, elem)
  109. elif t[0].isupper():
  110. return t
  111. return t
  112. def parse_array(n, t):
  113. name, length = n.split('[', 1)
  114. length = no_vk(length[:-1])
  115. type_ = "[{}]{}".format(length, do_type(t))
  116. return name, type_
  117. def remove_prefix(text, prefix):
  118. if text.startswith(prefix):
  119. return text[len(prefix):]
  120. return text
  121. def remove_suffix(text, suffix):
  122. if text.endswith(suffix):
  123. return text[:-len(suffix)]
  124. return text
  125. def to_snake_case(name):
  126. s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
  127. return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
  128. ext_suffixes = ["KHR", "EXT", "AMD", "NV", "NVX", "GOOGLE", "KHX"]
  129. ext_suffixes_title = [ext.title() for ext in ext_suffixes]
  130. def fix_arg(arg):
  131. name = arg
  132. # Remove useless pointer identifier in field name
  133. for p in ('s_', 'p_', 'pp_', 'pfn_'):
  134. if name.startswith(p):
  135. name = name[len(p)::]
  136. name = name.replace("__", "_")
  137. return name
  138. def fix_ext_suffix(name):
  139. for ext in ext_suffixes_title:
  140. if name.endswith(ext):
  141. start = name[:-len(ext)]
  142. end = name[-len(ext):].upper()
  143. return start+end
  144. return name
  145. def to_int(x):
  146. if x.startswith('0x'):
  147. return int(x, 16)
  148. return int(x)
  149. def is_int(x):
  150. try:
  151. int(x)
  152. return True
  153. except ValueError:
  154. return False
  155. def fix_enum_arg(name, is_flag_bit=False):
  156. # name = name.title()
  157. name = fix_ext_suffix(name)
  158. if len(name) > 0 and name[0].isdigit() and not name.startswith("0x") and not is_int(name):
  159. if name[1] == "D":
  160. name = name[1] + name[0] + (name[2:] if len(name) > 2 else "")
  161. else:
  162. name = "_"+name
  163. if is_flag_bit:
  164. name = name.replace("_BIT", "")
  165. return name
  166. def do_type(t, prev_name="", name=""):
  167. return convert_type(no_vk(t), prev_name, name).replace("FlagBits", "Flags")
  168. def parse_handles_def(f):
  169. f.write("// Handles types\n")
  170. handles = [h for h in re.findall(r"VK_DEFINE_HANDLE\(Vk(\w+)\)", src, re.S)]
  171. max_len = max(len(h) for h in handles)
  172. for h in handles:
  173. f.write("{} :: distinct Handle\n".format(h.ljust(max_len)))
  174. handles_non_dispatchable = [h for h in re.findall(r"VK_DEFINE_NON_DISPATCHABLE_HANDLE\(Vk(\w+)\)", src, re.S)]
  175. max_len = max(len(h) for h in handles_non_dispatchable)
  176. for h in handles_non_dispatchable:
  177. f.write("{} :: distinct NonDispatchableHandle\n".format(h.ljust(max_len)))
  178. flags_defs = set()
  179. def parse_flags_def(f):
  180. names = [n for n in re.findall(r"typedef VkFlags Vk(\w+?);", src)]
  181. global flags_defs
  182. flags_defs = set(names)
  183. class FlagError(ValueError):
  184. pass
  185. class IgnoreFlagError(ValueError):
  186. pass
  187. def fix_enum_name(name, prefix, suffix, is_flag_bit):
  188. name = remove_prefix(name, prefix)
  189. if suffix:
  190. name = remove_suffix(name, suffix)
  191. if name.startswith("0x"):
  192. if is_flag_bit:
  193. i = int(name, 16)
  194. if i == 0:
  195. raise IgnoreFlagError(i)
  196. v = int(math.log2(i))
  197. if 2**v != i:
  198. raise FlagError(i)
  199. return str(v)
  200. return name
  201. elif is_flag_bit:
  202. ignore = False
  203. try:
  204. if int(name) == 0:
  205. ignore = True
  206. except:
  207. pass
  208. if ignore:
  209. raise IgnoreFlagError()
  210. return fix_enum_arg(name, is_flag_bit)
  211. def fix_enum_value(value, prefix, suffix, is_flag_bit):
  212. v = no_vk(value)
  213. g = tokenize(BytesIO(v.encode('utf-8')).readline)
  214. tokens = [val for _, val, _, _, _ in g]
  215. assert len(tokens) > 2
  216. token = ''.join([t for t in tokens[1:-1] if t])
  217. token = fix_enum_name(token, prefix, suffix, is_flag_bit)
  218. return token
  219. def parse_constants(f):
  220. f.write("// General Constants\n")
  221. all_data = re.findall(r"#define VK_(\w+)\s*(.*?)U?\n", src, re.S)
  222. allowed_names = (
  223. "HEADER_VERSION",
  224. "MAX_DRIVER_NAME_SIZE",
  225. "MAX_DRIVER_INFO_SIZE",
  226. )
  227. allowed_data = [nv for nv in all_data if nv[0] in allowed_names]
  228. max_len = max(len(name) for name, value in allowed_data)
  229. for name, value in allowed_data:
  230. f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
  231. f.write("\n// Vulkan Video Constants\n")
  232. vulkan_video_data = re.findall(r"#define STD_(\w+)\s*(.*?)U?\n", src, re.S)
  233. max_len = max(len(name) for name, value in vulkan_video_data)
  234. for name, value in vulkan_video_data:
  235. f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
  236. f.write("\n// Vendor Constants\n")
  237. fixes = '|'.join(ext_suffixes)
  238. inner = r"((?:(?:" + fixes + r")\w+)|(?:\w+" + fixes + r"))"
  239. pattern = r"#define\s+VK_" + inner + r"\s*(.*?)\n"
  240. data = re.findall(pattern, src, re.S)
  241. number_suffix_re = re.compile(r"(\d+)[UuLlFf]")
  242. max_len = max(len(name) for name, value in data)
  243. for name, value in data:
  244. value = remove_prefix(value, 'VK_')
  245. v = number_suffix_re.findall(value)
  246. if v:
  247. value = v[0]
  248. f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
  249. f.write("\n")
  250. def parse_enums(f):
  251. f.write("import \"core:c\"\n\n")
  252. f.write("// Enums\n")
  253. data = re.findall(r"typedef enum Vk(\w+) {(.+?)} \w+;", src, re.S)
  254. data += re.findall(r"typedef enum Std(\w+) {(.+?)} \w+;", src, re.S)
  255. data.sort(key=lambda x: x[0])
  256. generated_flags = set()
  257. for name, fields in data:
  258. enum_name = name
  259. is_flag_bit = False
  260. if "FlagBits" in enum_name:
  261. is_flag_bit = True
  262. flags_name = enum_name.replace("FlagBits", "Flags")
  263. enum_name = enum_name.replace("FlagBits", "Flag")
  264. generated_flags.add(flags_name)
  265. f.write("{} :: distinct bit_set[{}; Flags]\n".format(flags_name, enum_name))
  266. if is_flag_bit:
  267. f.write("{} :: enum Flags {{\n".format(name.replace("FlagBits", "Flag")))
  268. else:
  269. f.write("{} :: enum c.int {{\n".format(name))
  270. prefix = to_snake_case(name).upper()
  271. suffix = None
  272. for ext in ext_suffixes:
  273. prefix_new = remove_suffix(prefix, "_"+ext)
  274. assert suffix is None
  275. if prefix_new != prefix:
  276. suffix = "_"+ext
  277. prefix = prefix_new
  278. break
  279. prefix = prefix.replace("_FLAG_BITS", "")
  280. prefix += "_"
  281. ff = []
  282. names_and_values = re.findall(r"VK_(\w+?) = (.*?)(?:,|})", fields, re.S)
  283. groups = []
  284. flags = {}
  285. for name, value in names_and_values:
  286. n = fix_enum_name(name, prefix, suffix, is_flag_bit)
  287. try:
  288. v = fix_enum_value(value, prefix, suffix, is_flag_bit)
  289. except FlagError as e:
  290. v = int(str(e))
  291. groups.append((n, v))
  292. continue
  293. except IgnoreFlagError as e:
  294. groups.append((n, 0))
  295. continue
  296. if n == v:
  297. continue
  298. try:
  299. flags[int(v)] = n
  300. except ValueError as e:
  301. pass
  302. if v == "NONE":
  303. continue
  304. ff.append((n, v))
  305. max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
  306. max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
  307. if max_flag_value < max_group_value:
  308. if (1<<max_flag_value)+1 < max_group_value:
  309. ff.append(('_MAX', 31))
  310. flags[31] = '_MAX'
  311. pass
  312. max_len = max([len(n) for n, v in ff] + [0])
  313. flag_names = set([n for n, v in ff])
  314. for n, v in ff:
  315. if is_flag_bit and not is_int(v) and v not in flag_names:
  316. print("Ignoring", n, "=", v)
  317. continue
  318. f.write("\t{} = {},".format(n.ljust(max_len), v))
  319. if n == "_MAX":
  320. f.write(" // Needed for the *_ALL bit set")
  321. f.write("\n")
  322. f.write("}\n\n")
  323. for n, v in groups:
  324. used_flags = []
  325. for i in range(0, 32):
  326. if 1<<i & v != 0:
  327. if i in flags:
  328. used_flags.append('.'+flags[i])
  329. else:
  330. used_flags.append('{}({})'.format(enum_name, i))
  331. # Make sure the 's' is after Flags and not the extension name.
  332. ext_suffix = ''
  333. for suffix in ext_suffixes:
  334. if not enum_name.endswith(suffix):
  335. continue
  336. ext_suffix = suffix
  337. enum_name = remove_suffix(enum_name, ext_suffix)
  338. break
  339. s = "{enum_name}s{ext_suffix}_{n} :: {enum_name}s{ext_suffix}{{".format(enum_name=enum_name, ext_suffix=ext_suffix, n=n)
  340. s += ', '.join(used_flags)
  341. s += "}\n"
  342. f.write(s)
  343. if len(groups) > 0:
  344. f.write("\n\n")
  345. unused_flags = [flag for flag in flags_defs if flag not in generated_flags]
  346. unused_flags.sort()
  347. max_len = max(len(flag) for flag in unused_flags)
  348. for flag in unused_flags:
  349. flag_name = flag.replace("Flags", "Flag")
  350. f.write("{} :: distinct bit_set[{}; Flags]\n".format(flag.ljust(max_len), flag_name))
  351. f.write("{} :: enum u32 {{}}\n".format(flag_name.ljust(max_len)))
  352. def parse_fake_enums(f):
  353. data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S)
  354. data.sort(key=lambda x: x[0])
  355. fake_enums = {}
  356. for type_name, name, value in data:
  357. if type_name in fake_enums:
  358. fake_enums[type_name].append((name,value))
  359. else:
  360. fake_enums[type_name] = [(name, value)]
  361. for name in fake_enums.keys():
  362. flags_name = name.replace("FlagBits", "Flags")
  363. enum_name = name.replace("FlagBits", "Flag")
  364. f.write("{} :: distinct bit_set[{}; Flags64]\n".format(flags_name, enum_name))
  365. f.write("{} :: enum Flags64 {{\n".format(name.replace("FlagBits", "Flag")))
  366. prefix = to_snake_case(name).upper()
  367. suffix = None
  368. for ext in ext_suffixes:
  369. prefix_new = remove_suffix(prefix, "_"+ext)
  370. assert suffix is None
  371. if prefix_new != prefix:
  372. suffix = "_"+ext
  373. prefix = prefix_new
  374. break
  375. prefix = prefix.replace("_FLAG_BITS2", "_2")
  376. prefix += "_"
  377. ff = []
  378. groups = []
  379. flags = {}
  380. names_and_values = fake_enums[name]
  381. for name, value in names_and_values:
  382. value = value.replace("ULL", "")
  383. n = fix_enum_name(name, prefix, suffix, True)
  384. try:
  385. v = fix_enum_value(value, prefix, suffix, True)
  386. except FlagError as e:
  387. v = int(str(e))
  388. groups.append((n, v))
  389. continue
  390. except IgnoreFlagError as e:
  391. groups.append((n, 0))
  392. continue
  393. if n == v:
  394. continue
  395. try:
  396. flags[int(v)] = n
  397. except ValueError as e:
  398. pass
  399. if v == "NONE":
  400. continue
  401. ff.append((n, v))
  402. max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
  403. max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
  404. if max_flag_value < max_group_value:
  405. if (1<<max_flag_value)+1 < max_group_value:
  406. ff.append(('_MAX', 31))
  407. flags[31] = '_MAX'
  408. pass
  409. max_len = max([len(n) for n, v in ff] + [0])
  410. flag_names = set([n for n, v in ff])
  411. for n, v in ff:
  412. if not is_int(v) and v not in flag_names:
  413. print("Ignoring", n, "=", v)
  414. continue
  415. f.write("\t{} = {},".format(n.ljust(max_len), v))
  416. if n == "_MAX":
  417. f.write(" // Needed for the *_ALL bit set")
  418. f.write("\n")
  419. f.write("}\n\n")
  420. def parse_structs(f):
  421. data = re.findall(r"typedef (struct|union) Vk(\w+?) {(.+?)} \w+?;", src, re.S)
  422. data += re.findall(r"typedef (struct|union) Std(\w+?) {(.+?)} \w+?;", src, re.S)
  423. for _type, name, fields in data:
  424. fields = re.findall(r"\s+(.+?)\s+([_a-zA-Z0-9[\]]+);", fields)
  425. f.write("{} :: struct ".format(name))
  426. if _type == "union":
  427. f.write("#raw_union ")
  428. f.write("{\n")
  429. prev_name = ""
  430. ffields = []
  431. for type_, fname in fields:
  432. # If the typename has a colon in it, then it is a C bit field.
  433. if ":" in type_:
  434. bit_field = type_.split(' ')
  435. # Get rid of empty spaces
  436. bit_field = list(filter(bool, bit_field))
  437. # [type, typename, :]
  438. assert len(bit_field) == 3, "Failed to parse the bit field!"
  439. bit_field_type = do_type(bit_field[0], prev_name, fname)
  440. f.write("\tbit_field: {},{}\n".format(bit_field_type, comment or ""))
  441. break
  442. if '[' in fname:
  443. fname, type_ = parse_array(fname, type_)
  444. comment = None
  445. n = fix_arg(fname)
  446. if "Flag_Bits" in type_:
  447. comment = " // only single bit set"
  448. t = do_type(type_, prev_name, fname)
  449. if n == "matrix":
  450. n = "mat"
  451. ffields.append(tuple([n, t, comment]))
  452. prev_name = fname
  453. max_len = max([len(n) for n, _, _ in ffields], default=0)
  454. for n, t, comment in ffields:
  455. k = max_len-len(n)+len(t)
  456. f.write("\t{}: {},{}\n".format(n, t.rjust(k), comment or ""))
  457. f.write("}\n\n")
  458. f.write("// Opaque structs\n")
  459. f.write(OPAQUE_STRUCTS)
  460. f.write("// Aliases\n")
  461. data = re.findall(r"typedef Vk(\w+?) Vk(\w+?);", src, re.S)
  462. aliases = []
  463. for _type, name in data:
  464. if _type == "Flags":
  465. continue
  466. name = name.replace("FlagBits", "Flag")
  467. _type = _type.replace("FlagBits", "Flag")
  468. if name.endswith("Flag2") or name.endswith("Flags2"):
  469. continue
  470. aliases.append((name, _type))
  471. max_len = max([len(n) for n, _ in aliases] + [0])
  472. for n, t in aliases:
  473. k = max_len
  474. f.write("{} :: {}\n".format(n.ljust(k), t))
  475. procedure_map = {}
  476. def parse_procedures(f):
  477. data = re.findall(r"typedef (\w+\*?) \(\w+ \*(\w+)\)\((.+?)\);", src, re.S)
  478. group_ff = {"Loader":[], "Misc":[], "Instance":[], "Device":[]}
  479. for rt, name, fields in data:
  480. proc_name = no_vk(name)
  481. pf = []
  482. prev_name = ""
  483. for type_, fname in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:,|$)", fields):
  484. curr_name = fix_arg(fname)
  485. pf.append((do_type(type_, prev_name, curr_name), curr_name))
  486. prev_name = curr_name
  487. data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""])
  488. ts = "proc \"c\" ({})".format(data_fields)
  489. rt_str = do_type(rt)
  490. if rt_str != "void":
  491. ts += " -> {}".format(rt_str)
  492. procedure_map[proc_name] = ts
  493. fields_types_name = [do_type(t) for t in re.findall(r"(?:\s*|)(.+?)\s*\w+(?:,|$)", fields)]
  494. table_name = fields_types_name[0]
  495. nn = (proc_name, ts)
  496. if table_name in ('Device', 'Queue', 'CommandBuffer') and proc_name != 'GetDeviceProcAddr':
  497. group_ff["Device"].append(nn)
  498. elif table_name in ('Instance', 'PhysicalDevice') or proc_name == 'GetDeviceProcAddr':
  499. group_ff["Instance"].append(nn)
  500. elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or proc_name == 'GetInstanceProcAddr':
  501. group_ff["Misc"].append(nn)
  502. else:
  503. group_ff["Loader"].append(nn)
  504. f.write("import \"core:c\"\n\n")
  505. for group_name, ff in group_ff.items():
  506. ff.sort()
  507. f.write("// {} Procedure Types\n".format(group_name))
  508. max_len = max(len(n) for n, t in ff)
  509. for n, t in ff:
  510. f.write("{} :: #type {}\n".format(n.ljust(max_len), t.replace('"c"', '"system"')))
  511. f.write("\n")
  512. def group_functions(f):
  513. data = re.findall(r"typedef (\w+\*?) \(\w+ \*(\w+)\)\((.+?)\);", src, re.S)
  514. group_map = {"Loader":[], "Instance":[], "Device":[]}
  515. for rt, vkname, fields in data:
  516. fields_types_name = [do_type(t) for t in re.findall(r"(?:\s*|)(.+?)\s*\w+(?:,|$)", fields)]
  517. table_name = fields_types_name[0]
  518. name = no_vk(vkname)
  519. nn = (fix_arg(name), fix_ext_suffix(name))
  520. if table_name in ('Device', 'Queue', 'CommandBuffer') and name != 'GetDeviceProcAddr':
  521. group_map["Device"].append(nn)
  522. elif table_name in ('Instance', 'PhysicalDevice') and name != 'ProcGetInstanceProcAddr' or name == 'GetDeviceProcAddr':
  523. group_map["Instance"].append(nn)
  524. elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or name == 'GetInstanceProcAddr':
  525. # Skip the allocation function and the dll entry point
  526. pass
  527. else:
  528. group_map["Loader"].append(nn)
  529. for _, group in group_map.items():
  530. group.sort()
  531. for group_name, group_lines in group_map.items():
  532. f.write("// {} Procedures\n".format(group_name))
  533. max_len = max(len(name) for name, _ in group_lines)
  534. for name, vk_name in group_lines:
  535. type_str = procedure_map[vk_name]
  536. f.write('{}: {}\n'.format(remove_prefix(name, "Proc"), name.rjust(max_len)))
  537. f.write("\n")
  538. f.write("load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {\n")
  539. for group_name, group_lines in group_map.items():
  540. f.write("\t// {} Procedures\n".format(group_name))
  541. max_len = max(len(name) for name, _ in group_lines)
  542. for name, vk_name in group_lines:
  543. k = max_len - len(name)
  544. f.write('\tset_proc_address(&{}, {}"vk{}")\n'.format(
  545. remove_prefix(name, 'Proc'),
  546. "".ljust(k),
  547. remove_prefix(vk_name, 'Proc'),
  548. ))
  549. f.write("\n")
  550. f.write("}\n\n")
  551. f.write("// Device Procedure VTable\n")
  552. f.write("Device_VTable :: struct {\n")
  553. max_len = max(len(name) for name, _ in group_map["Device"])
  554. for name, vk_name in group_map["Device"]:
  555. f.write('\t{}: {},\n'.format(remove_prefix(name, "Proc"), name.rjust(max_len)))
  556. f.write("}\n\n")
  557. f.write("load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable) {\n")
  558. for name, vk_name in group_map["Device"]:
  559. k = max_len - len(name)
  560. f.write('\tvtable.{}{} = auto_cast GetDeviceProcAddr(device, "vk{}")\n'.format(
  561. remove_prefix(name, 'Proc'),
  562. "".ljust(k),
  563. remove_prefix(vk_name, 'Proc'),
  564. ))
  565. f.write("}\n\n")
  566. f.write("load_proc_addresses_device :: proc(device: Device) {\n")
  567. max_len = max(len(name) for name, _ in group_map["Device"])
  568. for name, vk_name in group_map["Device"]:
  569. k = max_len - len(name)
  570. f.write('\t{}{} = auto_cast GetDeviceProcAddr(device, "vk{}")\n'.format(
  571. remove_prefix(name, 'Proc'),
  572. "".ljust(k),
  573. remove_prefix(vk_name, 'Proc'),
  574. ))
  575. f.write("}\n\n")
  576. f.write("load_proc_addresses_instance :: proc(instance: Instance) {\n")
  577. max_len = max(len(name) for name, _ in group_map["Instance"])
  578. for name, vk_name in group_map["Instance"]:
  579. k = max_len - len(name)
  580. f.write('\t{}{} = auto_cast GetInstanceProcAddr(instance, "vk{}")\n'.format(
  581. remove_prefix(name, 'Proc'),
  582. "".ljust(k),
  583. remove_prefix(vk_name, 'Proc'),
  584. ))
  585. f.write("\n\t// Device Procedures (may call into dispatch)\n")
  586. max_len = max(len(name) for name, _ in group_map["Device"])
  587. for name, vk_name in group_map["Device"]:
  588. k = max_len - len(name)
  589. f.write('\t{}{} = auto_cast GetInstanceProcAddr(instance, "vk{}")\n'.format(
  590. remove_prefix(name, 'Proc'),
  591. "".ljust(k),
  592. remove_prefix(vk_name, 'Proc'),
  593. ))
  594. f.write("}\n\n")
  595. f.write("load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) {\n")
  596. f.write("\tGetInstanceProcAddr = auto_cast vk_get_instance_proc_addr\n\n")
  597. max_len = max(len(name) for name, _ in group_map["Loader"])
  598. for name, vk_name in group_map["Loader"]:
  599. k = max_len - len(name)
  600. f.write('\t{}{} = auto_cast GetInstanceProcAddr(nil, "vk{}")\n'.format(
  601. remove_prefix(name, 'Proc'),
  602. "".ljust(k),
  603. remove_prefix(vk_name, 'Proc'),
  604. ))
  605. f.write("}\n\n")
  606. f.write("""
  607. load_proc_addresses :: proc{
  608. \tload_proc_addresses_global,
  609. \tload_proc_addresses_instance,
  610. \tload_proc_addresses_device,
  611. \tload_proc_addresses_device_vtable,
  612. \tload_proc_addresses_custom,
  613. }\n
  614. """[1::])
  615. BASE = """
  616. //
  617. // Vulkan wrapper generated from "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_core.h"
  618. //
  619. package vulkan
  620. """[1::]
  621. with open("../core.odin", 'w', encoding='utf-8') as f:
  622. f.write(BASE)
  623. f.write("""
  624. API_VERSION_1_0 :: (1<<22) | (0<<12) | (0)
  625. API_VERSION_1_1 :: (1<<22) | (1<<12) | (0)
  626. API_VERSION_1_2 :: (1<<22) | (2<<12) | (0)
  627. API_VERSION_1_3 :: (1<<22) | (3<<12) | (0)
  628. MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 {
  629. return (major<<22) | (minor<<12) | (patch)
  630. }
  631. // Base types
  632. Flags :: distinct u32
  633. Flags64 :: distinct u64
  634. DeviceSize :: distinct u64
  635. DeviceAddress :: distinct u64
  636. SampleMask :: distinct u32
  637. Handle :: distinct rawptr
  638. NonDispatchableHandle :: distinct u64
  639. SetProcAddressType :: #type proc(p: rawptr, name: cstring)
  640. RemoteAddressNV :: distinct rawptr // Declared inline before MemoryGetRemoteAddressInfoNV
  641. // Base constants
  642. LOD_CLAMP_NONE :: 1000.0
  643. REMAINING_MIP_LEVELS :: ~u32(0)
  644. REMAINING_ARRAY_LAYERS :: ~u32(0)
  645. WHOLE_SIZE :: ~u64(0)
  646. ATTACHMENT_UNUSED :: ~u32(0)
  647. TRUE :: 1
  648. FALSE :: 0
  649. QUEUE_FAMILY_IGNORED :: ~u32(0)
  650. SUBPASS_EXTERNAL :: ~u32(0)
  651. MAX_PHYSICAL_DEVICE_NAME_SIZE :: 256
  652. MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT :: 32
  653. UUID_SIZE :: 16
  654. MAX_MEMORY_TYPES :: 32
  655. MAX_MEMORY_HEAPS :: 16
  656. MAX_EXTENSION_NAME_SIZE :: 256
  657. MAX_DESCRIPTION_SIZE :: 256
  658. MAX_DEVICE_GROUP_SIZE :: 32
  659. LUID_SIZE_KHX :: 8
  660. LUID_SIZE :: 8
  661. MAX_QUEUE_FAMILY_EXTERNAL :: ~u32(1)
  662. MAX_GLOBAL_PRIORITY_SIZE_EXT :: 16
  663. QUEUE_FAMILY_EXTERNAL :: MAX_QUEUE_FAMILY_EXTERNAL
  664. """[1::])
  665. parse_constants(f)
  666. parse_handles_def(f)
  667. f.write("\n\n")
  668. parse_flags_def(f)
  669. with open("../enums.odin", 'w', encoding='utf-8') as f:
  670. f.write(BASE)
  671. f.write("\n")
  672. parse_enums(f)
  673. parse_fake_enums(f)
  674. f.write("\n\n")
  675. with open("../structs.odin", 'w', encoding='utf-8') as f:
  676. f.write(BASE)
  677. f.write("""
  678. import "core:c"
  679. when ODIN_OS == .Windows {
  680. \timport win32 "core:sys/windows"
  681. \tHINSTANCE :: win32.HINSTANCE
  682. \tHWND :: win32.HWND
  683. \tHMONITOR :: win32.HMONITOR
  684. \tHANDLE :: win32.HANDLE
  685. \tLPCWSTR :: win32.LPCWSTR
  686. \tSECURITY_ATTRIBUTES :: win32.SECURITY_ATTRIBUTES
  687. \tDWORD :: win32.DWORD
  688. \tLONG :: win32.LONG
  689. \tLUID :: win32.LUID
  690. } else {
  691. \tHINSTANCE :: distinct rawptr
  692. \tHWND :: distinct rawptr
  693. \tHMONITOR :: distinct rawptr
  694. \tHANDLE :: distinct rawptr
  695. \tLPCWSTR :: ^u16
  696. \tSECURITY_ATTRIBUTES :: struct {}
  697. \tDWORD :: u32
  698. \tLONG :: c.long
  699. \tLUID :: struct {
  700. \t\tLowPart: DWORD,
  701. \t\tHighPart: LONG,
  702. \t}
  703. }
  704. CAMetalLayer :: struct {}
  705. MTLBuffer_id :: rawptr
  706. MTLTexture_id :: rawptr
  707. MTLSharedEvent_id :: rawptr
  708. MTLDevice_id :: rawptr
  709. MTLCommandQueue_id :: rawptr
  710. /********************************/
  711. """)
  712. f.write("\n")
  713. parse_structs(f)
  714. f.write("\n\n")
  715. with open("../procedures.odin", 'w', encoding='utf-8') as f:
  716. f.write(BASE)
  717. f.write("\n")
  718. parse_procedures(f)
  719. f.write("\n")
  720. group_functions(f)