1
# Copyright © 2020 Hoe Hao Cheng
3
# Permission is hereby granted, free of charge, to any person obtaining a
4
# copy of this software and associated documentation files (the "Software"),
5
# to deal in the Software without restriction, including without limitation
6
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
# and/or sell copies of the Software, and to permit persons to whom the
8
# Software is furnished to do so, subject to the following conditions:
10
# The above copyright notice and this permission notice (including the next
11
# paragraph) shall be included in all copies or substantial portions of the
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
from xml.etree import ElementTree
25
from typing import List,Tuple
28
device_version = (1,0,0)
29
struct_version = (1,0)
31
def __init__(self, version, struct=()):
32
self.device_version = version
35
self.struct_version = (version[0], version[1])
37
self.struct_version = struct
39
# e.g. "VK_MAKE_VERSION(1,2,0)"
41
return ("VK_MAKE_VERSION("
42
+ str(self.device_version[0])
44
+ str(self.device_version[1])
46
+ str(self.device_version[2])
51
return (str(self.struct_version[0])+str(self.struct_version[1]))
53
# the sType of the extension's struct
54
# e.g. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT
55
# for VK_EXT_transform_feedback and struct="FEATURES"
56
def stype(self, struct: str):
57
return ("VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_"
58
+ str(self.struct_version[0]) + "_" + str(self.struct_version[1])
65
is_nonstandard = False
69
# these are specific to zink_device_info.py:
70
has_properties = False
74
# these are specific to zink_instance.py:
77
def __init__(self, name, alias="", required=False, nonstandard=False,
78
properties=False, features=False, conditions=None, guard=False):
81
self.is_required = required
82
self.is_nonstandard = nonstandard
83
self.has_properties = properties
84
self.has_features = features
85
self.enable_conds = conditions
88
if alias == "" and (properties == True or features == True):
89
raise RuntimeError("alias must be available when properties and/or features are used")
91
# e.g.: "VK_EXT_robustness2" -> "robustness2"
93
return '_'.join(self.name.split('_')[2:])
95
# e.g.: "VK_EXT_robustness2" -> "EXT_robustness2"
96
def name_with_vendor(self):
99
# e.g.: "VK_EXT_robustness2" -> "Robustness2"
100
def name_in_camel_case(self):
101
return "".join([x.title() for x in self.name.split('_')[2:]])
103
# e.g.: "VK_EXT_robustness2" -> "VK_EXT_ROBUSTNESS2_EXTENSION_NAME"
104
# do note that inconsistencies exist, i.e. we have
105
# VK_EXT_ROBUSTNESS_2_EXTENSION_NAME defined in the headers, but then
106
# we also have VK_KHR_MAINTENANCE1_EXTENSION_NAME
107
def extension_name(self):
108
return self.name.upper() + "_EXTENSION_NAME"
110
# generate a C string literal for the extension
111
def extension_name_literal(self):
112
return '"' + self.name + '"'
114
# get the field in zink_device_info that refers to the extension's
115
# feature/properties struct
116
# e.g. rb2_<suffix> for VK_EXT_robustness2
117
def field(self, suffix: str):
118
return self.alias + '_' + suffix
120
def physical_device_struct(self, struct: str):
121
if self.name_in_camel_case().endswith(struct):
124
return ("VkPhysicalDevice"
125
+ self.name_in_camel_case()
129
# the sType of the extension's struct
130
# e.g. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT
131
# for VK_EXT_transform_feedback and struct="FEATURES"
132
def stype(self, struct: str):
133
return ("VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_"
134
+ self.pure_name().upper()
138
# e.g. EXT in VK_EXT_robustness2
140
return self.name.split('_')[1]
145
class ExtensionRegistryEntry:
146
# type of extension - right now it's either "instance" or "device"
148
# the version in which the extension is promoted to core VK
150
# functions added by the extension are referred to as "commands" in the registry
151
device_commands = None
152
pdevice_commands = None
153
instance_commands = None
155
features_struct = None
156
properties_struct = None
157
# some instance extensions are locked behind certain platforms
160
class ExtensionRegistry:
161
# key = extension name, value = registry entry
164
def __init__(self, vkxml_path: str):
165
vkxml = ElementTree.parse(vkxml_path)
167
commands_type = dict()
169
platform_guards = dict()
171
for cmd in vkxml.findall("commands/command"):
172
name = cmd.find("./proto/name")
174
if name is not None and name.text:
175
commands_type[name.text] = cmd.find("./param/type").text
176
elif cmd.get("name") is not None:
177
aliases[cmd.get("name")] = cmd.get("alias")
179
for (cmd, alias) in aliases.items():
180
commands_type[cmd] = commands_type[alias]
182
for platform in vkxml.findall("platforms/platform"):
183
name = platform.get("name")
184
guard = platform.get("protect")
185
platform_guards[name] = guard
187
for ext in vkxml.findall("extensions/extension"):
188
# Reserved extensions are marked with `supported="disabled"`
189
if ext.get("supported") == "disabled":
192
name = ext.attrib["name"]
194
entry = ExtensionRegistryEntry()
195
entry.ext_type = ext.attrib["type"]
196
entry.promoted_in = self.parse_promotedto(ext.get("promotedto"))
198
entry.device_commands = []
199
entry.pdevice_commands = []
200
entry.instance_commands = []
202
for cmd in ext.findall("require/command"):
203
cmd_name = cmd.get("name")
205
if commands_type[cmd_name] in ("VkDevice", "VkCommandBuffer", "VkQueue"):
206
entry.device_commands.append(cmd_name)
207
elif commands_type[cmd_name] in ("VkPhysicalDevice"):
208
entry.pdevice_commands.append(cmd_name)
210
entry.instance_commands.append(cmd_name)
213
for enum in ext.findall("require/enum"):
214
enum_name = enum.get("name")
215
enum_extends = enum.get("extends")
216
# we are only interested in VK_*_EXTENSION_NAME, which does not
217
# have an "extends" attribute
219
entry.constants.append(enum_name)
221
for ty in ext.findall("require/type"):
222
ty_name = ty.get("name")
223
if (self.is_features_struct(ty_name) and
224
entry.features_struct is None):
225
entry.features_struct = ty_name
226
elif (self.is_properties_struct(ty_name) and
227
entry.properties_struct is None):
228
entry.properties_struct = ty_name
230
if ext.get("platform") is not None:
231
entry.platform_guard = platform_guards[ext.get("platform")]
233
self.registry[name] = entry
235
def in_registry(self, ext_name: str):
236
return ext_name in self.registry
238
def get_registry_entry(self, ext_name: str):
239
if self.in_registry(ext_name):
240
return self.registry[ext_name]
242
# Parses e.g. "VK_VERSION_x_y" to integer tuple (x, y)
243
# For any erroneous inputs, None is returned
244
def parse_promotedto(self, promotedto: str):
247
if promotedto and promotedto.startswith("VK_VERSION_"):
248
(major, minor) = promotedto.split('_')[-2:]
249
result = (int(major), int(minor))
253
def is_features_struct(self, struct: str):
254
return re.match(r"VkPhysicalDevice.*Features.*", struct) is not None
256
def is_properties_struct(self, struct: str):
257
return re.match(r"VkPhysicalDevice.*Properties.*", struct) is not None