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