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