1#!/usr/bin/env python3 2# 3# Copyright 2019 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Provide the utilities for framework generation. 18""" 19 20import os 21import subprocess 22import xml.etree.ElementTree as element_tree 23 24# Extensions unsupported on Android. 25_BLOCKED_EXTENSIONS = [ 26 'VK_EXT_acquire_xlib_display', 27 'VK_EXT_direct_mode_display', 28 'VK_EXT_directfb_surface', 29 'VK_EXT_display_control', 30 'VK_EXT_display_surface_counter', 31 'VK_EXT_full_screen_exclusive', 32 'VK_EXT_headless_surface', 33 'VK_EXT_metal_surface', 34 'VK_FUCHSIA_imagepipe_surface', 35 'VK_GGP_stream_descriptor_surface', 36 'VK_HUAWEI_subpass_shading', 37 'VK_KHR_display', 38 'VK_KHR_display_swapchain', 39 'VK_KHR_external_fence_win32', 40 'VK_KHR_external_memory_win32', 41 'VK_KHR_external_semaphore_win32', 42 'VK_KHR_mir_surface', 43 'VK_KHR_wayland_surface', 44 'VK_KHR_win32_keyed_mutex', 45 'VK_KHR_win32_surface', 46 'VK_KHR_xcb_surface', 47 'VK_KHR_xlib_surface', 48 'VK_MVK_ios_surface', 49 'VK_MVK_macos_surface', 50 'VK_NN_vi_surface', 51 'VK_NV_acquire_winrt_display', 52 'VK_NV_cooperative_matrix', 53 'VK_NV_coverage_reduction_mode', 54 'VK_NV_external_memory_win32', 55 'VK_NV_win32_keyed_mutex', 56 'VK_NVX_image_view_handle', 57 'VK_QNX_screen_surface', 58] 59 60# Extensions having functions exported by the loader. 61_EXPORTED_EXTENSIONS = [ 62 'VK_ANDROID_external_memory_android_hardware_buffer', 63 'VK_KHR_android_surface', 64 'VK_KHR_surface', 65 'VK_KHR_swapchain', 66] 67 68# Functions optional on Android even if extension is advertised. 69_OPTIONAL_COMMANDS = [ 70 'vkGetSwapchainGrallocUsageANDROID', 71 'vkGetSwapchainGrallocUsage2ANDROID', 72] 73 74# Dict for mapping dispatch table to a type. 75_DISPATCH_TYPE_DICT = { 76 'VkInstance ': 'Instance', 77 'VkPhysicalDevice ': 'Instance', 78 'VkDevice ': 'Device', 79 'VkQueue ': 'Device', 80 'VkCommandBuffer ': 'Device' 81} 82 83# Dict for mapping a function to its alias. 84alias_dict = {} 85 86# List of all the Vulkan functions. 87command_list = [] 88 89# Dict for mapping a function to an extension. 90extension_dict = {} 91 92# Dict for mapping a function to all its parameters. 93param_dict = {} 94 95# Dict for mapping a function to its return type. 96return_type_dict = {} 97 98# List of the sorted Vulkan version codes. e.g. '1_0', '1_1'. 99version_code_list = [] 100 101# Dict for mapping a function to the core Vulkan API version. 102version_dict = {} 103 104# Dict for mapping a promoted instance extension to the core Vulkan API version. 105promoted_inst_ext_dict = {} 106 107 108def indent(num): 109 """Returns the requested indents. 110 111 Args: 112 num: Number of the 4-space indents. 113 """ 114 return ' ' * num 115 116 117def copyright_and_warning(year): 118 """Returns the standard copyright and warning codes. 119 120 Args: 121 year: An integer year for the copyright. 122 """ 123 return """\ 124/* 125 * Copyright """ + str(year) + """ The Android Open Source Project 126 * 127 * Licensed under the Apache License, Version 2.0 (the "License"); 128 * you may not use this file except in compliance with the License. 129 * You may obtain a copy of the License at 130 * 131 * http://www.apache.org/licenses/LICENSE-2.0 132 * 133 * Unless required by applicable law or agreed to in writing, software 134 * distributed under the License is distributed on an "AS IS" BASIS, 135 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136 * See the License for the specific language governing permissions and 137 * limitations under the License. 138 */ 139 140// WARNING: This file is generated. See ../README.md for instructions. 141 142""" 143 144 145def run_clang_format(args): 146 """Run clang format on the file. 147 148 Args: 149 args: The file to be formatted. 150 """ 151 clang_call = ['clang-format', '--style', 'file', '-i', args] 152 subprocess.check_call(clang_call) 153 154 155def is_extension_internal(ext): 156 """Returns true if an extension is internal to the loader and drivers. 157 158 The loader should not enumerate this extension. 159 160 Args: 161 ext: Vulkan extension name. 162 """ 163 return ext == 'VK_ANDROID_native_buffer' 164 165 166def base_name(cmd): 167 """Returns a function name without the 'vk' prefix. 168 169 Args: 170 cmd: Vulkan function name. 171 """ 172 return cmd[2:] 173 174 175def base_ext_name(ext): 176 """Returns an extension name without the 'VK_' prefix. 177 178 Args: 179 ext: Vulkan extension name. 180 """ 181 return ext[3:] 182 183 184def version_code(version): 185 """Returns the version code from a version string. 186 187 Args: 188 version: Vulkan version string. 189 """ 190 return version[11:] 191 192 193def version_2_api_version(version): 194 """Returns the api version from a version string. 195 196 Args: 197 version: Vulkan version string. 198 """ 199 return 'VK_API' + version[2:] 200 201 202def is_function_supported(cmd): 203 """Returns true if a function is core or from a supportable extension. 204 205 Args: 206 cmd: Vulkan function name. 207 """ 208 if cmd not in extension_dict: 209 return True 210 else: 211 if extension_dict[cmd] not in _BLOCKED_EXTENSIONS: 212 return True 213 return False 214 215 216def get_dispatch_table_type(cmd): 217 """Returns the dispatch table type for a function. 218 219 Args: 220 cmd: Vulkan function name. 221 """ 222 if cmd not in param_dict: 223 return None 224 225 if param_dict[cmd]: 226 return _DISPATCH_TYPE_DICT.get(param_dict[cmd][0][0], 'Global') 227 return 'Global' 228 229 230def is_globally_dispatched(cmd): 231 """Returns true if the function is global, which is not dispatched. 232 233 Only global functions and functions handled in the loader top without calling 234 into lower layers are not dispatched. 235 236 Args: 237 cmd: Vulkan function name. 238 """ 239 return is_function_supported(cmd) and get_dispatch_table_type(cmd) == 'Global' 240 241 242def is_instance_dispatched(cmd): 243 """Returns true for functions that can have instance-specific dispatch. 244 245 Args: 246 cmd: Vulkan function name. 247 """ 248 return (is_function_supported(cmd) and 249 get_dispatch_table_type(cmd) == 'Instance') 250 251 252def is_device_dispatched(cmd): 253 """Returns true for functions that can have device-specific dispatch. 254 255 Args: 256 cmd: Vulkan function name. 257 """ 258 return is_function_supported(cmd) and get_dispatch_table_type(cmd) == 'Device' 259 260 261def is_extension_exported(ext): 262 """Returns true if an extension has functions exported by the loader. 263 264 E.g. applications can directly link to an extension function. 265 266 Args: 267 ext: Vulkan extension name. 268 """ 269 return ext in _EXPORTED_EXTENSIONS 270 271 272def is_function_exported(cmd): 273 """Returns true if a function is exported from the Android Vulkan library. 274 275 Functions in the core API and in loader extensions are exported. 276 277 Args: 278 cmd: Vulkan function name. 279 """ 280 if is_function_supported(cmd): 281 if cmd in extension_dict: 282 return is_extension_exported(extension_dict[cmd]) 283 return True 284 return False 285 286 287def is_instance_dispatch_table_entry(cmd): 288 """Returns true if a function is exported and instance-dispatched. 289 290 Args: 291 cmd: Vulkan function name. 292 """ 293 if cmd == 'vkEnumerateDeviceLayerProperties': 294 # deprecated, unused internally - @dbd33bc 295 return False 296 return is_function_exported(cmd) and is_instance_dispatched(cmd) 297 298 299def is_device_dispatch_table_entry(cmd): 300 """Returns true if a function is exported and device-dispatched. 301 302 Args: 303 cmd: Vulkan function name. 304 """ 305 return is_function_exported(cmd) and is_device_dispatched(cmd) 306 307 308def init_proc(name, f): 309 """Emits code to invoke INIT_PROC or INIT_PROC_EXT. 310 311 Args: 312 name: Vulkan function name. 313 f: Output file handle. 314 """ 315 f.write(indent(1)) 316 if name in extension_dict: 317 f.write('INIT_PROC_EXT(' + base_ext_name(extension_dict[name]) + ', ') 318 else: 319 f.write('INIT_PROC(') 320 321 if name in _OPTIONAL_COMMANDS: 322 f.write('false, ') 323 elif version_dict[name] == 'VK_VERSION_1_0': 324 f.write('true, ') 325 else: 326 f.write('false, ') 327 328 if is_instance_dispatched(name): 329 f.write('instance, ') 330 else: 331 f.write('dev, ') 332 333 f.write(base_name(name) + ');\n') 334 335 336def parse_vulkan_registry(): 337 """Parses Vulkan registry into the below global variables. 338 339 alias_dict 340 command_list 341 extension_dict 342 param_dict 343 return_type_dict 344 version_code_list 345 version_dict 346 promoted_inst_ext_dict 347 """ 348 registry = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', 349 'external', 'vulkan-headers', 'registry', 'vk.xml') 350 tree = element_tree.parse(registry) 351 root = tree.getroot() 352 for commands in root.iter('commands'): 353 for command in commands: 354 if command.tag == 'command': 355 parameter_list = [] 356 protoset = False 357 cmd_name = '' 358 cmd_type = '' 359 if command.get('alias') is not None: 360 alias = command.get('alias') 361 cmd_name = command.get('name') 362 alias_dict[cmd_name] = alias 363 command_list.append(cmd_name) 364 param_dict[cmd_name] = param_dict[alias].copy() 365 return_type_dict[cmd_name] = return_type_dict[alias] 366 for params in command: 367 if params.tag == 'param': 368 param_type = '' 369 if params.text is not None and params.text.strip(): 370 param_type = params.text.strip() + ' ' 371 type_val = params.find('type') 372 param_type = param_type + type_val.text 373 if type_val.tail is not None: 374 param_type += type_val.tail.strip() + ' ' 375 pname = params.find('name') 376 param_name = pname.text 377 if pname.tail is not None and pname.tail.strip(): 378 parameter_list.append( 379 (param_type, param_name, pname.tail.strip())) 380 else: 381 parameter_list.append((param_type, param_name)) 382 if params.tag == 'proto': 383 for c in params: 384 if c.tag == 'type': 385 cmd_type = c.text 386 if c.tag == 'name': 387 cmd_name = c.text 388 protoset = True 389 command_list.append(cmd_name) 390 return_type_dict[cmd_name] = cmd_type 391 if protoset: 392 param_dict[cmd_name] = parameter_list.copy() 393 394 for exts in root.iter('extensions'): 395 for extension in exts: 396 apiversion = 'VK_VERSION_1_0' 397 if extension.tag == 'extension': 398 extname = extension.get('name') 399 if (extension.get('type') == 'instance' and 400 extension.get('promotedto') is not None): 401 promoted_inst_ext_dict[extname] = \ 402 version_2_api_version(extension.get('promotedto')) 403 for req in extension: 404 if req.get('feature') is not None: 405 apiversion = req.get('feature') 406 for commands in req: 407 if commands.tag == 'command': 408 cmd_name = commands.get('name') 409 if cmd_name not in extension_dict: 410 extension_dict[cmd_name] = extname 411 version_dict[cmd_name] = apiversion 412 413 for feature in root.iter('feature'): 414 apiversion = feature.get('name') 415 for req in feature: 416 for command in req: 417 if command.tag == 'command': 418 cmd_name = command.get('name') 419 if cmd_name in command_list: 420 version_dict[cmd_name] = apiversion 421 422 version_code_set = set() 423 for version in version_dict.values(): 424 version_code_set.add(version_code(version)) 425 for code in sorted(version_code_set): 426 version_code_list.append(code) 427