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