1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045 |
- import re
- import urllib.request as req
- from tokenize import tokenize
- from io import BytesIO
- import string
- import os.path
- import math
- file_and_urls = [
- ("vk_platform.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_platform.h', True),
- ("vulkan_core.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_core.h', False),
- ("vk_layer.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_layer.h', True),
- ("vk_icd.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vk_icd.h', True),
- ("vulkan_win32.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_win32.h', False),
- ("vulkan_metal.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_metal.h', False),
- ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False),
- ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False),
- ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False),
- ("vulkan_xlib.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xlib.h', False),
- ("vulkan_xcb.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xcb.h', False),
- # Vulkan Video
- ("vulkan_video_codec_av1std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False),
- ("vulkan_video_codec_av1std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False),
- ("vulkan_video_codec_av1std_encode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_encode.h', False),
- ("vulkan_video_codec_h264std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h264std.h', False),
- ("vulkan_video_codec_h264std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h264std_decode.h', False),
- ("vulkan_video_codec_h264std_encode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h264std_encode.h', False),
- ("vulkan_video_codec_h265std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h265std.h', False),
- ("vulkan_video_codec_h265std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h265std_decode.h', False),
- ("vulkan_video_codec_h265std_encode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_h265std_encode.h', False),
- ]
- for file, url, _ in file_and_urls:
- if not os.path.isfile(file):
- with open(file, 'w', encoding='utf-8') as f:
- f.write(req.urlopen(url).read().decode('utf-8'))
- src = ""
- for file, _, skip in file_and_urls:
- if skip: continue
- with open(file, 'r', encoding='utf-8') as f:
- src += f.read()
- def no_vk(t):
- t = t.replace('PFN_vk_icd', 'Procicd')
- t = t.replace('PFN_vk', 'Proc')
- t = t.replace('PFN_', 'Proc')
- t = t.replace('PFN_', 'Proc')
- t = re.sub('(?:Vk|VK_)?(\\w+)', '\\1', t)
- # Vulkan Video
- t = re.sub('(?:Std|STD_|VK_STD)?(\\w+)', '\\1', t)
- return t
- OPAQUE_STRUCTS = """
- wl_surface :: struct {} // Opaque struct defined by Wayland
- wl_display :: struct {} // Opaque struct defined by Wayland
- xcb_connection_t :: struct {} // Opaque struct defined by xcb
- IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework
- """
- def convert_type(t, prev_name, curr_name):
- table = {
- "Bool32": 'b32',
- "float": 'f32',
- "double": 'f64',
- "uint32_t": 'u32',
- "uint64_t": 'u64',
- "size_t": 'int',
- 'int16_t': 'i16',
- 'int32_t': 'i32',
- 'int64_t': 'i64',
- 'int': 'c.int',
- 'uint8_t': 'u8',
- 'int8_t': 'i8',
- "uint16_t": 'u16',
- "char": "byte",
- "void": "void",
- "void*": "rawptr",
- "void *": "rawptr",
- "char*": 'cstring',
- "const uint32_t* const*": "^[^]u32",
- "const void*": 'rawptr',
- "const char*": 'cstring',
- "const char* const*": '[^]cstring',
- "const ObjectTableEntryNVX* const*": "^^ObjectTableEntryNVX",
- "const void* const *": "[^]rawptr",
- "const AccelerationStructureGeometryKHR* const*": "^[^]AccelerationStructureGeometryKHR",
- "const AccelerationStructureBuildRangeInfoKHR* const*": "^[^]AccelerationStructureBuildRangeInfoKHR",
- "const MicromapUsageEXT* const*": "^[^]MicromapUsageEXT",
- "struct BaseOutStructure": "BaseOutStructure",
- "struct BaseInStructure": "BaseInStructure",
- "struct wl_display": "wl_display",
- "struct wl_surface": "wl_surface",
- "Display": "XlibDisplay",
- "Window": "XlibWindow",
- "VisualID": "XlibVisualID",
- 'v': '',
- }
- if t in table.keys():
- return table[t]
- if t == "":
- return t
- if t.startswith("const"):
- t = convert_type(t[6:], prev_name, curr_name)
- elif t.endswith("*"):
- pointer = "^"
- ttype = t[:len(t)-1]
- elem = convert_type(ttype, prev_name, curr_name)
- if curr_name.endswith("s") or curr_name.endswith("Table"):
- if prev_name.endswith("Count") or prev_name.endswith("Counts"):
- pointer = "[^]"
- elif curr_name.startswith("pp"):
- if elem.startswith("[^]"):
- pass
- else:
- pointer = "[^]"
- elif curr_name.startswith("p"):
- pointer = "[^]"
- if curr_name and elem.endswith("Flags"):
- pointer = "[^]"
- return "{}{}".format(pointer, elem)
- elif t[0].isupper():
- return t
- return t
- def parse_array(n, t):
- name, length = n.split('[', 1)
- length = no_vk(length[:-1])
- type_ = "[{}]{}".format(length, do_type(t))
- return name, type_
- def remove_prefix(text, prefix):
- if text.startswith(prefix):
- return text[len(prefix):]
- return text
- def remove_suffix(text, suffix):
- if text.endswith(suffix):
- return text[:-len(suffix)]
- return text
- def to_snake_case(name):
- s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
- return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
- ext_suffixes = ["KHR", "EXT", "AMD", "NV", "NVX", "GOOGLE", "KHX"]
- ext_suffixes_title = [ext.title() for ext in ext_suffixes]
- def fix_arg(arg):
- name = arg
- # Remove useless pointer identifier in field name
- for p in ('s_', 'p_', 'pp_', 'pfn_'):
- if name.startswith(p):
- name = name[len(p)::]
- name = name.replace("__", "_")
- return name
- def fix_ext_suffix(name):
- for ext in ext_suffixes_title:
- if name.endswith(ext):
- start = name[:-len(ext)]
- end = name[-len(ext):].upper()
- return start+end
- return name
- def to_int(x):
- if x.startswith('0x'):
- return int(x, 16)
- return int(x)
- def is_int(x):
- try:
- int(x)
- return True
- except ValueError:
- return False
- def fix_enum_arg(name, is_flag_bit=False):
- # name = name.title()
- name = fix_ext_suffix(name)
- if len(name) > 0 and name[0].isdigit() and not name.startswith("0x") and not is_int(name):
- if name[1] == "D":
- name = name[1] + name[0] + (name[2:] if len(name) > 2 else "")
- else:
- name = "_"+name
- if is_flag_bit:
- name = name.replace("_BIT", "")
- return name
- def do_type(t, prev_name="", name=""):
- return convert_type(no_vk(t), prev_name, name).replace("FlagBits", "Flags")
- def parse_handles_def(f):
- f.write("// Handles types\n")
- handles = [h for h in re.findall(r"VK_DEFINE_HANDLE\(Vk(\w+)\)", src, re.S)]
- max_len = max(len(h) for h in handles)
- for h in handles:
- f.write("{} :: distinct Handle\n".format(h.ljust(max_len)))
- handles_non_dispatchable = [h for h in re.findall(r"VK_DEFINE_NON_DISPATCHABLE_HANDLE\(Vk(\w+)\)", src, re.S)]
- max_len = max(len(h) for h in handles_non_dispatchable)
- for h in handles_non_dispatchable:
- f.write("{} :: distinct NonDispatchableHandle\n".format(h.ljust(max_len)))
- flags_defs = set()
- def parse_flags_def(f):
- names = [n for n in re.findall(r"typedef VkFlags Vk(\w+?);", src)]
- global flags_defs
- flags_defs = set(names)
- class FlagError(ValueError):
- pass
- class IgnoreFlagError(ValueError):
- pass
- def fix_enum_name(name, prefix, suffix, is_flag_bit):
- name = remove_prefix(name, prefix)
- if suffix:
- name = remove_suffix(name, suffix)
- if name.startswith("0x"):
- if is_flag_bit:
- i = int(name, 16)
- if i == 0:
- raise IgnoreFlagError(i)
- v = int(math.log2(i))
- if 2**v != i:
- raise FlagError(i)
- return str(v)
- return name
- elif is_flag_bit:
- ignore = False
- try:
- if int(name) == 0:
- ignore = True
- except:
- pass
- if ignore:
- raise IgnoreFlagError()
- return fix_enum_arg(name, is_flag_bit)
- def fix_enum_value(value, prefix, suffix, is_flag_bit):
- v = no_vk(value)
- g = tokenize(BytesIO(v.encode('utf-8')).readline)
- tokens = [val for _, val, _, _, _ in g]
- assert len(tokens) > 2
- token = ''.join([t for t in tokens[1:-1] if t])
- token = fix_enum_name(token, prefix, suffix, is_flag_bit)
- return token
- def parse_constants(f):
- f.write("// General Constants\n")
- all_data = re.findall(r"#define VK_(\w+)\s*(.*?)U?\n", src, re.S)
- allowed_names = (
- "HEADER_VERSION",
- "MAX_DRIVER_NAME_SIZE",
- "MAX_DRIVER_INFO_SIZE",
- )
- allowed_data = [nv for nv in all_data if nv[0] in allowed_names]
- max_len = max(len(name) for name, value in allowed_data)
- for name, value in allowed_data:
- f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
- f.write("\n// Vulkan Video Constants\n")
- vulkan_video_data = re.findall(r"#define STD_(\w+)\s*(.*?)U?\n", src, re.S)
- max_len = max(len(name) for name, value in vulkan_video_data)
- for name, value in vulkan_video_data:
- f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
- f.write("\n// Vulkan Video Codec Constants\n")
- vulkan_video_codec_allowed_suffixes = (
- "_EXTENSION_NAME",
- )
- vulkan_video_codec_data = re.findall(r"#define VK_STD_(\w+)\s*(.*?)U?\n", src, re.S)
- vulkan_video_codec_allowed_data = [nv for nv in vulkan_video_codec_data if nv[0].endswith(vulkan_video_codec_allowed_suffixes)]
- max_len = max(len(name) for name, value in vulkan_video_codec_allowed_data)
- for name, value in vulkan_video_codec_allowed_data:
- f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
- f.write("\n// Vendor Constants\n")
- fixes = '|'.join(ext_suffixes)
- inner = r"((?:(?:" + fixes + r")\w+)|(?:\w+" + fixes + r"))"
- pattern = r"#define\s+VK_" + inner + r"\s*(.*?)\n"
- data = re.findall(pattern, src, re.S)
- number_suffix_re = re.compile(r"(\d+)[UuLlFf]")
- max_len = max(len(name) for name, value in data)
- for name, value in data:
- value = remove_prefix(value, 'VK_')
- v = number_suffix_re.findall(value)
- if v:
- value = v[0]
- f.write("{}{} :: {}\n".format(name, "".rjust(max_len-len(name)), value))
- f.write("\n")
- def parse_enums(f):
- f.write("import \"core:c\"\n\n")
- f.write("// Enums\n")
- data = re.findall(r"typedef enum (\w+) {(.+?)} \w+;", src, re.S)
- data = [(no_vk(n), f) for n, f in data]
- data.sort(key=lambda x: x[0])
- generated_flags = set()
- for name, fields in data:
- enum_name = name
- is_flag_bit = False
- if "FlagBits" in enum_name:
- is_flag_bit = True
- flags_name = enum_name.replace("FlagBits", "Flags")
- enum_name = enum_name.replace("FlagBits", "Flag")
- generated_flags.add(flags_name)
- f.write("{} :: distinct bit_set[{}; Flags]\n".format(flags_name, enum_name))
- if is_flag_bit:
- f.write("{} :: enum Flags {{\n".format(name.replace("FlagBits", "Flag")))
- else:
- f.write("{} :: enum c.int {{\n".format(name))
- prefix = to_snake_case(name).upper()
- suffix = None
- for ext in ext_suffixes:
- prefix_new = remove_suffix(prefix, "_"+ext)
- assert suffix is None
- if prefix_new != prefix:
- suffix = "_"+ext
- prefix = prefix_new
- break
- prefix = prefix.replace("_FLAG_BITS", "")
- prefix += "_"
- ff = []
- names_and_values = re.findall(r"VK_(\w+?) = (.*?)(?:,|})", fields, re.S)
- groups = []
- flags = {}
- for name, value in names_and_values:
- n = fix_enum_name(name, prefix, suffix, is_flag_bit)
- try:
- v = fix_enum_value(value, prefix, suffix, is_flag_bit)
- except FlagError as e:
- v = int(str(e))
- groups.append((n, v))
- continue
- except IgnoreFlagError as e:
- groups.append((n, 0))
- continue
- if n == v:
- continue
- try:
- flags[int(v)] = n
- except ValueError as e:
- pass
- if v == "NONE":
- continue
- ff.append((n, v))
- max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
- max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
- if max_flag_value < max_group_value:
- if (1<<max_flag_value)+1 < max_group_value:
- ff.append(('_MAX', 31))
- flags[31] = '_MAX'
- pass
- max_len = max([len(n) for n, v in ff] + [0])
- flag_names = set([n for n, v in ff])
- for n, v in ff:
- if is_flag_bit and not is_int(v) and v not in flag_names:
- print("Ignoring", n, "=", v)
- continue
- f.write("\t{} = {},".format(n.ljust(max_len), v))
- if n == "_MAX":
- f.write(" // Needed for the *_ALL bit set")
- f.write("\n")
- f.write("}\n\n")
- for n, v in groups:
- used_flags = []
- for i in range(0, 32):
- if 1<<i & v != 0:
- if i in flags:
- used_flags.append('.'+flags[i])
- else:
- used_flags.append('{}({})'.format(enum_name, i))
- # Make sure the 's' is after Flags and not the extension name.
- ext_suffix = ''
- for suffix in ext_suffixes:
- if not enum_name.endswith(suffix):
- continue
- ext_suffix = suffix
- enum_name = remove_suffix(enum_name, ext_suffix)
- break
- s = "{enum_name}s{ext_suffix}_{n} :: {enum_name}s{ext_suffix}{{".format(enum_name=enum_name, ext_suffix=ext_suffix, n=n)
- s += ', '.join(used_flags)
- s += "}\n"
- f.write(s)
- if len(groups) > 0:
- f.write("\n\n")
- unused_flags = [flag for flag in flags_defs if flag not in generated_flags]
- unused_flags.sort()
- max_len = max(len(flag) for flag in unused_flags)
- for flag in unused_flags:
- flag_name = flag.replace("Flags", "Flag")
- f.write("{} :: distinct bit_set[{}; Flags]\n".format(flag.ljust(max_len), flag_name))
- f.write("{} :: enum u32 {{}}\n".format(flag_name.ljust(max_len)))
- def parse_fake_enums(f):
- data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S)
- data.sort(key=lambda x: x[0])
- fake_enums = {}
- for type_name, name, value in data:
- if type_name in fake_enums:
- fake_enums[type_name].append((name,value))
- else:
- fake_enums[type_name] = [(name, value)]
- for name in fake_enums.keys():
- flags_name = name.replace("FlagBits", "Flags")
- enum_name = name.replace("FlagBits", "Flag")
- f.write("{} :: distinct bit_set[{}; Flags64]\n".format(flags_name, enum_name))
- f.write("{} :: enum Flags64 {{\n".format(name.replace("FlagBits", "Flag")))
- prefix = to_snake_case(name).upper()
- suffix = None
- for ext in ext_suffixes:
- prefix_new = remove_suffix(prefix, "_"+ext)
- assert suffix is None
- if prefix_new != prefix:
- suffix = "_"+ext
- prefix = prefix_new
- break
- prefix = prefix.replace("_FLAG_BITS2", "_2")
- prefix += "_"
- ff = []
- groups = []
- flags = {}
- names_and_values = fake_enums[name]
- for name, value in names_and_values:
- value = value.replace("ULL", "")
- n = fix_enum_name(name, prefix, suffix, True)
- try:
- v = fix_enum_value(value, prefix, suffix, True)
- except FlagError as e:
- v = int(str(e))
- groups.append((n, v))
- continue
- except IgnoreFlagError as e:
- groups.append((n, 0))
- continue
- if n == v:
- continue
- try:
- flags[int(v)] = n
- except ValueError as e:
- pass
- if v == "NONE":
- continue
- ff.append((n, v))
- max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
- max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
- if max_flag_value < max_group_value:
- if (1<<max_flag_value)+1 < max_group_value:
- ff.append(('_MAX', 31))
- flags[31] = '_MAX'
- pass
- max_len = max([len(n) for n, v in ff] + [0])
- flag_names = set([n for n, v in ff])
- for n, v in ff:
- if not is_int(v) and v not in flag_names:
- print("Ignoring", n, "=", v)
- continue
- f.write("\t{} = {},".format(n.ljust(max_len), v))
- if n == "_MAX":
- f.write(" // Needed for the *_ALL bit set")
- f.write("\n")
- f.write("}\n\n")
- class BitfieldError(ValueError):
- pass
- def bitfield_type_to_size(type_):
- if type_ == 'u8':
- return 8
- if type_ == 'u16':
- return 16
- if type_ == 'u32':
- return 32
- if type_ == 'u64':
- return 64
- if 'Flags' in type_:
- return 32
- else:
- raise BitfieldError(f"Invalid type for bitfield: {type_}")
- def bitfield_size_to_type(size):
- if size == 8:
- return 'u8'
- if size == 16:
- return 'u16'
- if size == 32:
- return 'u32'
- if size == 64:
- return 'u64'
- else:
- raise BitfieldError(f"Invalid size for bitfield: {size}")
- class Bitfield:
- class Field:
- def __init__(self, name, type_, bitsize):
- self.name = name
- self.type = type_
- self.bitsize = bitsize
-
- def __init__(self, type_):
- self.bitsize = bitfield_type_to_size(type_)
- self.type = bitfield_size_to_type(self.bitsize)
- self.fields_bitsize = 0
- self.fields = []
- def add_field(self, name, type_, bitsize):
- self.fields.append(Bitfield.Field(name, type_, bitsize))
- self.fields_bitsize += bitsize
-
- def write(self, f, name=None, indent=0, justify=True):
- max_name = 1 if not justify else max([len(f.name) for f in self.fields], default=0)
- max_type = 1 if not justify else max([len(f.type) for f in self.fields], default=0)
- is_bit_set = all([f.bitsize == 1 or f.name == "reserved" for f in self.fields])
- if is_bit_set and name is None:
- raise BitfieldError(f"bit_set can not be anonymous")
-
- if is_bit_set:
- if not name.endswith("Flags"):
- raise BitfieldError(f"bit_set name should end with 'Flags': {name}")
- enum_name = re.sub('Flags$', 'Flag', name)
- f.write("{}{} :: distinct bit_set[{}; {}]\n".format('\t' * indent, name, enum_name, self.type))
- f.write("{}{} :: enum {} {{\n".format('\t' * indent, enum_name, self.type))
- for field in self.fields:
- if field.name != "reserved":
- f.write("{}{},\n".format('\t' * (indent + 1), field.name))
- f.write(('\t' * indent) + "}\n")
-
- else:
- f.write("{}{} bit_field {} {{\n".format('\t' * indent, name + ' ::' if name else 'using _:', self.type))
- for field in self.fields:
- type_ = field.type.replace("Flags", "Flag")
- f.write("{}{} {} | {},\n".format(
- '\t' * (indent + 1),
- (field.name + ":").ljust(max_name + 1),
- type_.ljust(max_type),
- field.bitsize))
- f.write(('\t' * indent) + "}" + ("," if name is None else "") + "\n")
- def parse_structs(f):
- data = re.findall(r"typedef (struct|union) Vk(\w+?) {(.+?)} \w+?;", src, re.S)
- data += re.findall(r"typedef (struct|union) Std(\w+?) {(.+?)} \w+?;", src, re.S)
- for _type, struct_name, fields in data:
- fields = re.findall(r"\s+(.+?)[\s:]+([_a-zA-Z0-9[\]]+);", fields)
- prev_name = ""
- ffields = []
- bitfield = None
- for type_, fname in fields:
- # If the field name only has a number in it, then it is a C bit field.
- # We will collect all the bit fields and then create either a bit_field or a bit_set.
- if is_int(fname):
- bf_field = type_.split(' ')
- # Get rid of empty spaces
- bf_field = list(filter(bool, bf_field))
- # [type, fieldname]
- assert len(bf_field) == 2, "Failed to parse the bit field!"
- field_type = do_type(bf_field[0])
- bitsize = int(fname)
- # Close the set because the field size is greater than the bitfield type
- if bitfield and (bitfield.fields_bitsize + bitsize) > bitfield_type_to_size(field_type):
- ffields.append(tuple([None, bitfield]))
- bitfield = None
- # Raise an error if the field type size is greater than the bitfield type size
- if bitfield is not None and bitfield_type_to_size(bitfield.type) < bitfield_type_to_size(field_type):
- raise BitfieldError(f"field will not fit in the bitfield: {bitfield.type} < {field_type}")
- # Create a new bitfield if we don't have one
- if not bitfield:
- bitfield = Bitfield(field_type)
- # Add the field to the bitfield
- bitfield.add_field(bf_field[1], field_type, bitsize)
- continue
- # Close the bitfield because this is not a field
- elif bitfield:
- ffields.append(tuple([None, bitfield]))
- bitfield = None
- if '[' in fname:
- fname, type_ = parse_array(fname, type_)
- n = fix_arg(fname)
- if "Flag_Bits" in type_:
- # comment = " // only single bit set"
- raise BitfieldError("only single bit set")
- t = do_type(type_, prev_name, fname)
- if n == "matrix":
- n = "mat"
- ffields.append(tuple([n, t]))
- prev_name = fname
- # Close the bitfield because we have no more fields
- if bitfield:
- ffields.append(tuple([None, bitfield]))
- # Write the struct as a bitfield if it only has bit fields
- if len(ffields) == 1 and ffields[0][0] is None:
- ffields[0][1].write(f, struct_name, 0, True)
- f.write("\n")
- # Write as a normal struct (or union) if it has other fields
- # and inject anonymous bitfields into the struct if there are any
- else:
- has_anon_bitfield = any(name is None for name, _ in ffields)
- max_len = 1 if has_anon_bitfield else max([len(n) for n, _ in ffields], default=0)
- f.write("{} :: struct ".format(struct_name))
- if _type == "union":
- f.write("#raw_union ")
- f.write("{\n")
- for name, type_ in ffields:
- if name is None:
- # Inject an anonymous bitfield into the struct
- type_.write(f, None, indent=1, justify=True)
- else:
- f.write("\t{} {},\n".format((name + ":").ljust(max_len + 1), type_))
- f.write("}\n\n")
- f.write("// Opaque structs\n")
- f.write(OPAQUE_STRUCTS)
- f.write("// Aliases\n")
- data = re.findall(r"typedef Vk(\w+?) Vk(\w+?);", src, re.S)
- aliases = []
- for _type, name in data:
- if _type == "Flags":
- continue
- name = name.replace("FlagBits", "Flag")
- _type = _type.replace("FlagBits", "Flag")
- if name.endswith("Flag2") or name.endswith("Flags2"):
- continue
- aliases.append((name, _type))
- max_len = max([len(n) for n, _ in aliases] + [0])
- for n, t in aliases:
- k = max_len
- f.write("{} :: {}\n".format(n.ljust(k), t))
- procedure_map = {}
- def parse_procedures(f):
- data = re.findall(r"typedef (\w+\*?) \(\w+ \*(\w+)\)\((.+?)\);", src, re.S)
- group_ff = {"Loader":[], "Misc":[], "Instance":[], "Device":[]}
- for rt, name, fields in data:
- proc_name = no_vk(name)
- pf = []
- prev_name = ""
- for type_, fname, array_len in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:\[(\d+)\])?(?:,|$)", fields):
- curr_name = fix_arg(fname)
- ty = do_type(type_, prev_name, curr_name)
- if array_len != "":
- ty = f"^[{array_len}]{ty}"
- pf.append((ty, curr_name))
- prev_name = curr_name
- data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""])
- ts = "proc \"c\" ({})".format(data_fields)
- rt_str = do_type(rt)
- if rt_str != "void":
- ts += " -> {}".format(rt_str)
- procedure_map[proc_name] = ts
- fields_types_name = [do_type(t) for t in re.findall(r"(?:\s*|)(.+?)\s*\w+(?:,|$)", fields)]
- table_name = fields_types_name[0]
- nn = (proc_name, ts)
- if table_name in ('Device', 'Queue', 'CommandBuffer') and proc_name != 'GetDeviceProcAddr':
- group_ff["Device"].append(nn)
- elif table_name in ('Instance', 'PhysicalDevice') or proc_name == 'GetDeviceProcAddr':
- group_ff["Instance"].append(nn)
- elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or proc_name == 'GetInstanceProcAddr':
- group_ff["Misc"].append(nn)
- else:
- group_ff["Loader"].append(nn)
- f.write("import \"core:c\"\n\n")
- for group_name, ff in group_ff.items():
- ff.sort()
- f.write("// {} Procedure Types\n".format(group_name))
- max_len = max(len(n) for n, t in ff)
- for n, t in ff:
- f.write("{} :: #type {}\n".format(n.ljust(max_len), t.replace('"c"', '"system"')))
- f.write("\n")
- def group_functions(f):
- data = re.findall(r"typedef (\w+\*?) \(\w+ \*(\w+)\)\((.+?)\);", src, re.S)
- group_map = {"Loader":[], "Instance":[], "Device":[]}
- for rt, vkname, fields in data:
- fields_types_name = [do_type(t) for t in re.findall(r"(?:\s*|)(.+?)\s*\w+(?:,|$)", fields)]
- table_name = fields_types_name[0]
- name = no_vk(vkname)
- nn = (fix_arg(name), fix_ext_suffix(name))
- if table_name in ('Device', 'Queue', 'CommandBuffer') and name != 'GetDeviceProcAddr':
- group_map["Device"].append(nn)
- elif table_name in ('Instance', 'PhysicalDevice') and name != 'ProcGetInstanceProcAddr' or name == 'GetDeviceProcAddr':
- group_map["Instance"].append(nn)
- elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or name == 'GetInstanceProcAddr':
- # Skip the allocation function and the dll entry point
- pass
- else:
- group_map["Loader"].append(nn)
- for _, group in group_map.items():
- group.sort()
- for group_name, group_lines in group_map.items():
- f.write("// {} Procedures\n".format(group_name))
- max_len = max(len(name) for name, _ in group_lines)
- for name, vk_name in group_lines:
- type_str = procedure_map[vk_name]
- f.write('{}: {}\n'.format(remove_prefix(name, "Proc"), name.rjust(max_len)))
- f.write("\n")
- f.write("load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {\n")
- for group_name, group_lines in group_map.items():
- f.write("\t// {} Procedures\n".format(group_name))
- max_len = max(len(name) for name, _ in group_lines)
- for name, vk_name in group_lines:
- k = max_len - len(name)
- f.write('\tset_proc_address(&{}, {}"vk{}")\n'.format(
- remove_prefix(name, 'Proc'),
- "".ljust(k),
- remove_prefix(vk_name, 'Proc'),
- ))
- f.write("\n")
- f.write("}\n\n")
- f.write("// Device Procedure VTable\n")
- f.write("Device_VTable :: struct {\n")
- max_len = max(len(name) for name, _ in group_map["Device"])
- for name, vk_name in group_map["Device"]:
- f.write('\t{}: {},\n'.format(remove_prefix(name, "Proc"), name.rjust(max_len)))
- f.write("}\n\n")
- f.write("load_proc_addresses_device_vtable :: proc(device: Device, vtable: ^Device_VTable) {\n")
- for name, vk_name in group_map["Device"]:
- k = max_len - len(name)
- f.write('\tvtable.{}{} = auto_cast GetDeviceProcAddr(device, "vk{}")\n'.format(
- remove_prefix(name, 'Proc'),
- "".ljust(k),
- remove_prefix(vk_name, 'Proc'),
- ))
- f.write("}\n\n")
- f.write("load_proc_addresses_device :: proc(device: Device) {\n")
- max_len = max(len(name) for name, _ in group_map["Device"])
- for name, vk_name in group_map["Device"]:
- k = max_len - len(name)
- f.write('\t{}{} = auto_cast GetDeviceProcAddr(device, "vk{}")\n'.format(
- remove_prefix(name, 'Proc'),
- "".ljust(k),
- remove_prefix(vk_name, 'Proc'),
- ))
- f.write("}\n\n")
- f.write("load_proc_addresses_instance :: proc(instance: Instance) {\n")
- max_len = max(len(name) for name, _ in group_map["Instance"])
- for name, vk_name in group_map["Instance"]:
- k = max_len - len(name)
- f.write('\t{}{} = auto_cast GetInstanceProcAddr(instance, "vk{}")\n'.format(
- remove_prefix(name, 'Proc'),
- "".ljust(k),
- remove_prefix(vk_name, 'Proc'),
- ))
- f.write("\n\t// Device Procedures (may call into dispatch)\n")
- max_len = max(len(name) for name, _ in group_map["Device"])
- for name, vk_name in group_map["Device"]:
- k = max_len - len(name)
- f.write('\t{}{} = auto_cast GetInstanceProcAddr(instance, "vk{}")\n'.format(
- remove_prefix(name, 'Proc'),
- "".ljust(k),
- remove_prefix(vk_name, 'Proc'),
- ))
- f.write("}\n\n")
- f.write("load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) {\n")
- f.write("\tGetInstanceProcAddr = auto_cast vk_get_instance_proc_addr\n\n")
- max_len = max(len(name) for name, _ in group_map["Loader"])
- for name, vk_name in group_map["Loader"]:
- k = max_len - len(name)
- f.write('\t{}{} = auto_cast GetInstanceProcAddr(nil, "vk{}")\n'.format(
- remove_prefix(name, 'Proc'),
- "".ljust(k),
- remove_prefix(vk_name, 'Proc'),
- ))
- f.write("}\n\n")
- f.write("""
- load_proc_addresses :: proc{
- \tload_proc_addresses_global,
- \tload_proc_addresses_instance,
- \tload_proc_addresses_device,
- \tload_proc_addresses_device_vtable,
- \tload_proc_addresses_custom,
- }\n
- """[1::])
- BASE = """
- //
- // Vulkan wrapper generated from "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/master/include/vulkan/vulkan_core.h"
- //
- package vulkan
- """[1::]
- with open("../core.odin", 'w', encoding='utf-8') as f:
- f.write(BASE)
- f.write("""
- // Core API
- API_VERSION_1_0 :: (1<<22) | (0<<12) | (0)
- API_VERSION_1_1 :: (1<<22) | (1<<12) | (0)
- API_VERSION_1_2 :: (1<<22) | (2<<12) | (0)
- API_VERSION_1_3 :: (1<<22) | (3<<12) | (0)
- API_VERSION_1_4 :: (1<<22) | (4<<12) | (0)
- MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 {
- \treturn (major<<22) | (minor<<12) | (patch)
- }
- // Base types
- Flags :: distinct u32
- Flags64 :: distinct u64
- DeviceSize :: distinct u64
- DeviceAddress :: distinct u64
- SampleMask :: distinct u32
- Handle :: distinct rawptr
- NonDispatchableHandle :: distinct u64
- SetProcAddressType :: #type proc(p: rawptr, name: cstring)
- RemoteAddressNV :: distinct rawptr // Declared inline before MemoryGetRemoteAddressInfoNV
- // Base constants
- LOD_CLAMP_NONE :: 1000.0
- REMAINING_MIP_LEVELS :: ~u32(0)
- REMAINING_ARRAY_LAYERS :: ~u32(0)
- WHOLE_SIZE :: ~u64(0)
- ATTACHMENT_UNUSED :: ~u32(0)
- TRUE :: 1
- FALSE :: 0
- QUEUE_FAMILY_IGNORED :: ~u32(0)
- SUBPASS_EXTERNAL :: ~u32(0)
- MAX_PHYSICAL_DEVICE_NAME_SIZE :: 256
- MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT :: 32
- UUID_SIZE :: 16
- MAX_MEMORY_TYPES :: 32
- MAX_MEMORY_HEAPS :: 16
- MAX_EXTENSION_NAME_SIZE :: 256
- MAX_DESCRIPTION_SIZE :: 256
- MAX_DEVICE_GROUP_SIZE :: 32
- LUID_SIZE_KHX :: 8
- LUID_SIZE :: 8
- MAX_QUEUE_FAMILY_EXTERNAL :: ~u32(1)
- MAX_GLOBAL_PRIORITY_SIZE :: 16
- MAX_GLOBAL_PRIORITY_SIZE_EXT :: MAX_GLOBAL_PRIORITY_SIZE
- QUEUE_FAMILY_EXTERNAL :: MAX_QUEUE_FAMILY_EXTERNAL
- // Vulkan Video API Constants
- VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 :: (1<<22) | (0<<12) | (0)
- VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0 :: (1<<22) | (0<<12) | (0)
- VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 :: (1<<22) | (0<<12) | (0)
- VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 :: (1<<22) | (0<<12) | (0)
- VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 :: (1<<22) | (0<<12) | (0)
- VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 :: (1<<22) | (0<<12) | (0)
- VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION :: VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0
- VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION :: VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0
- VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION :: VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0
- VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION :: VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0
- VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION :: VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0
- VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION :: VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0
- MAKE_VIDEO_STD_VERSION :: MAKE_VERSION
- """[1::])
- parse_constants(f)
- parse_handles_def(f)
- f.write("\n\n")
- parse_flags_def(f)
- with open("../enums.odin", 'w', encoding='utf-8') as f:
- f.write(BASE)
- f.write("\n")
- parse_enums(f)
- parse_fake_enums(f)
- f.write("\n\n")
- with open("../structs.odin", 'w', encoding='utf-8') as f:
- f.write(BASE)
- f.write("""
- import "core:c"
- import win32 "core:sys/windows"
- _ :: win32
- import "vendor:x11/xlib"
- _ :: xlib
- when ODIN_OS == .Windows {
- \tHINSTANCE :: win32.HINSTANCE
- \tHWND :: win32.HWND
- \tHMONITOR :: win32.HMONITOR
- \tHANDLE :: win32.HANDLE
- \tLPCWSTR :: win32.LPCWSTR
- \tSECURITY_ATTRIBUTES :: win32.SECURITY_ATTRIBUTES
- \tDWORD :: win32.DWORD
- \tLONG :: win32.LONG
- \tLUID :: win32.LUID
- } else {
- \tHINSTANCE :: distinct rawptr
- \tHWND :: distinct rawptr
- \tHMONITOR :: distinct rawptr
- \tHANDLE :: distinct rawptr
- \tLPCWSTR :: ^u16
- \tSECURITY_ATTRIBUTES :: struct {}
- \tDWORD :: u32
- \tLONG :: c.long
- \tLUID :: struct {
- \t\tLowPart: DWORD,
- \t\tHighPart: LONG,
- \t}
- }
- when xlib.IS_SUPPORTED {
- \tXlibDisplay :: xlib.Display
- \tXlibWindow :: xlib.Window
- \tXlibVisualID :: xlib.VisualID
- } else {
- \tXlibDisplay :: struct {} // Opaque struct defined by Xlib
- \tXlibWindow :: c.ulong
- \tXlibVisualID :: c.ulong
- }
- xcb_visualid_t :: u32
- xcb_window_t :: u32
- CAMetalLayer :: struct {}
- MTLBuffer_id :: rawptr
- MTLTexture_id :: rawptr
- MTLSharedEvent_id :: rawptr
- MTLDevice_id :: rawptr
- MTLCommandQueue_id :: rawptr
- /********************************/
- """)
- f.write("\n")
- parse_structs(f)
- f.write("\n\n")
- with open("../procedures.odin", 'w', encoding='utf-8') as f:
- f.write(BASE)
- f.write("\n")
- parse_procedures(f)
- f.write("\n")
- group_functions(f)
|