1#!/usr/bin/env python3 2# 3# VK 4# 5# Copyright (c) 2015-2016 The Khronos Group Inc. 6# Copyright (c) 2015-2016 Valve Corporation 7# Copyright (c) 2015-2016 LunarG, Inc. 8# Copyright (c) 2015-2016 Google Inc. 9# 10# Permission is hereby granted, free of charge, to any person obtaining a copy 11# of this software and/or associated documentation files (the "Materials"), to 12# deal in the Materials without restriction, including without limitation the 13# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14# sell copies of the Materials, and to permit persons to whom the Materials 15# are furnished to do so, subject to the following conditions: 16# 17# The above copyright notice(s) and this permission notice shall be included 18# in all copies or substantial portions of the Materials. 19# 20# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23# 24# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 26# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 27# USE OR OTHER DEALINGS IN THE MATERIALS 28# 29# Author: Tobin Ehlis <tobine@google.com> 30# Author: Courtney Goeltzenleuchter <courtneygo@google.com> 31# Author: Jon Ashburn <jon@lunarg.com> 32# Author: Mark Lobodzinski <mark@lunarg.com> 33# Author: Mike Stroyan <stroyan@google.com> 34# Author: Tony Barbour <tony@LunarG.com> 35# Author: Chia-I Wu <olv@google.com> 36# Author: Gwan-gyeong Mun <kk.moon@samsung.com> 37 38import sys 39import os 40import re 41 42import vulkan 43import vk_helper 44from source_line_info import sourcelineinfo 45from collections import defaultdict 46 47def proto_is_global(proto): 48 global_function_names = [ 49 "CreateInstance", 50 "EnumerateInstanceLayerProperties", 51 "EnumerateInstanceExtensionProperties", 52 "EnumerateDeviceLayerProperties", 53 "EnumerateDeviceExtensionProperties", 54 "CreateXcbSurfaceKHR", 55 "GetPhysicalDeviceXcbPresentationSupportKHR", 56 "CreateXlibSurfaceKHR", 57 "GetPhysicalDeviceXlibPresentationSupportKHR", 58 "CreateWaylandSurfaceKHR", 59 "GetPhysicalDeviceWaylandPresentationSupportKHR", 60 "CreateMirSurfaceKHR", 61 "GetPhysicalDeviceMirPresentationSupportKHR", 62 "CreateAndroidSurfaceKHR", 63 "CreateWin32SurfaceKHR", 64 "GetPhysicalDeviceWin32PresentationSupportKHR" 65 ] 66 if proto.params[0].ty == "VkInstance" or proto.params[0].ty == "VkPhysicalDevice" or proto.name in global_function_names: 67 return True 68 else: 69 return False 70 71def wsi_name(ext_name): 72 wsi_prefix = "" 73 if 'Xcb' in ext_name: 74 wsi_prefix = 'XCB' 75 elif 'Xlib' in ext_name: 76 wsi_prefix = 'XLIB' 77 elif 'Win32' in ext_name: 78 wsi_prefix = 'WIN32' 79 elif 'Mir' in ext_name: 80 wsi_prefix = 'MIR' 81 elif 'Wayland' in ext_name: 82 wsi_prefix = 'WAYLAND' 83 elif 'Android' in ext_name: 84 wsi_prefix = 'ANDROID' 85 else: 86 wsi_prefix = '' 87 return wsi_prefix 88 89def wsi_ifdef(ext_name): 90 wsi_prefix = wsi_name(ext_name) 91 if not wsi_prefix: 92 return '' 93 else: 94 return "#ifdef VK_USE_PLATFORM_%s_KHR" % wsi_prefix 95 96def wsi_endif(ext_name): 97 wsi_prefix = wsi_name(ext_name) 98 if not wsi_prefix: 99 return '' 100 else: 101 return "#endif // VK_USE_PLATFORM_%s_KHR" % wsi_prefix 102 103def generate_get_proc_addr_check(name): 104 return " if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \ 105 " return NULL;" % ((name,) * 3) 106 107def ucc_to_U_C_C(CamelCase): 108 temp = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', CamelCase) 109 return re.sub('([a-z0-9])([A-Z])', r'\1_\2', temp).upper() 110 111# Parse complete struct chain and add any new ndo_uses to the dict 112def gather_object_uses_in_struct(obj_list, struct_type): 113 struct_uses = {} 114 if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict: 115 struct_type = vk_helper.typedef_rev_dict[struct_type] 116 # Parse elements of this struct param to identify objects and/or arrays of objects 117 for m in sorted(vk_helper.struct_dict[struct_type]): 118 array_len = "%s" % (str(vk_helper.struct_dict[struct_type][m]['array_size'])) 119 base_type = vk_helper.struct_dict[struct_type][m]['type'] 120 mem_name = vk_helper.struct_dict[struct_type][m]['name'] 121 if array_len != '0': 122 mem_name = "%s[%s]" % (mem_name, array_len) 123 if base_type in obj_list: 124 #if array_len not in ndo_uses: 125 # struct_uses[array_len] = [] 126 #struct_uses[array_len].append("%s%s,%s" % (name_prefix, struct_name, base_type)) 127 struct_uses[mem_name] = base_type 128 elif vk_helper.is_type(base_type, 'struct'): 129 sub_uses = gather_object_uses_in_struct(obj_list, base_type) 130 if len(sub_uses) > 0: 131 struct_uses[mem_name] = sub_uses 132 return struct_uses 133 134# For the given list of object types, Parse the given list of params 135# and return dict of params that use one of the obj_list types 136# Format of the dict is that terminal elements have <name>,<type> 137# non-terminal elements will have <name>[<array_size>] 138# TODO : This analysis could be done up-front at vk_helper time 139def get_object_uses(obj_list, params): 140 obj_uses = {} 141 local_decls = {} 142 param_count = 'NONE' # track params that give array sizes 143 for p in params: 144 base_type = p.ty.replace('const ', '').strip('*') 145 array_len = '' 146 is_ptr = False 147 if 'count' in p.name.lower(): 148 param_count = p.name 149 ptr_txt = '' 150 if '*' in p.ty: 151 is_ptr = True 152 ptr_txt = '*' 153 if base_type in obj_list: 154 if is_ptr and 'const' in p.ty and param_count != 'NONE': 155 array_len = "[%s]" % param_count 156 # Non-arrays we can overwrite in place, but need local decl for arrays 157 local_decls[p.name] = '%s%s' % (base_type, ptr_txt) 158 #if array_len not in obj_uses: 159 # obj_uses[array_len] = {} 160 # obj_uses[array_len][p.name] = base_type 161 obj_uses["%s%s" % (p.name, array_len)] = base_type 162 elif vk_helper.is_type(base_type, 'struct'): 163 struct_name = p.name 164 if 'NONE' != param_count: 165 struct_name = "%s[%s]" % (struct_name, param_count) 166 struct_uses = gather_object_uses_in_struct(obj_list, base_type) 167 if len(struct_uses) > 0: 168 obj_uses[struct_name] = struct_uses 169 # This is a top-level struct w/ uses below it, so need local decl 170 local_decls['%s' % (p.name)] = '%s%s' % (base_type, ptr_txt) 171 return (obj_uses, local_decls) 172 173class Subcommand(object): 174 def __init__(self, argv): 175 self.argv = argv 176 self.headers = vulkan.headers 177 self.protos = vulkan.protos 178 self.no_addr = False 179 self.layer_name = "" 180 self.lineinfo = sourcelineinfo() 181 self.wsi = sys.argv[1] 182 183 def run(self): 184 print(self.generate()) 185 186 def generate(self): 187 copyright = self.generate_copyright() 188 header = self.generate_header() 189 body = self.generate_body() 190 footer = self.generate_footer() 191 192 contents = [] 193 if copyright: 194 contents.append(copyright) 195 if header: 196 contents.append(header) 197 if body: 198 contents.append(body) 199 if footer: 200 contents.append(footer) 201 202 return "\n\n".join(contents) 203 204 def generate_copyright(self): 205 return """/* THIS FILE IS GENERATED. DO NOT EDIT. */ 206 207/* 208 * Copyright (c) 2015-2016 The Khronos Group Inc. 209 * Copyright (c) 2015-2016 Valve Corporation 210 * Copyright (c) 2015-2016 LunarG, Inc. 211 * Copyright (c) 2015 Google, Inc. 212 * 213 * Permission is hereby granted, free of charge, to any person obtaining a copy 214 * of this software and/or associated documentation files (the "Materials"), to 215 * deal in the Materials without restriction, including without limitation the 216 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 217 * sell copies of the Materials, and to permit persons to whom the Materials 218 * are furnished to do so, subject to the following conditions: 219 * 220 * The above copyright notice(s) and this permission notice shall be included 221 * in all copies or substantial portions of the Materials. 222 * 223 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 224 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 225 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 226 * 227 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 228 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 229 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 230 * USE OR OTHER DEALINGS IN THE MATERIALS 231 * 232 * Author: Tobin Ehlis <tobine@google.com> 233 * Author: Courtney Goeltzenleuchter <courtneygo@google.com> 234 * Author: Jon Ashburn <jon@lunarg.com> 235 * Author: Mark Lobodzinski <mark@lunarg.com> 236 * Author: Mike Stroyan <stroyan@google.com> 237 * Author: Tony Barbour <tony@LunarG.com> 238 */""" 239 240 def generate_header(self): 241 return "\n".join(["#include <" + h + ">" for h in self.headers]) 242 243 def generate_body(self): 244 pass 245 246 def generate_footer(self): 247 pass 248 249 # Return set of printf '%' qualifier and input to that qualifier 250 def _get_printf_params(self, vk_type, name, output_param, cpp=False): 251 # TODO : Need ENUM and STRUCT checks here 252 if vk_helper.is_type(vk_type, 'enum'):#"_TYPE" in vk_type: # TODO : This should be generic ENUM check 253 return ("%s", "string_%s(%s)" % (vk_type.replace('const ', '').strip('*'), name)) 254 if "char*" == vk_type: 255 return ("%s", name) 256 if "uint64" in vk_type: 257 if '*' in vk_type: 258 return ("%lu", "*%s" % name) 259 return ("%lu", name) 260 if vk_type.strip('*') in vulkan.object_non_dispatch_list: 261 if '*' in vk_type: 262 return ("%lu", "%s" % name) 263 return ("%lu", "%s" % name) 264 if "size" in vk_type: 265 if '*' in vk_type: 266 return ("%lu", "(unsigned long)*%s" % name) 267 return ("%lu", "(unsigned long)%s" % name) 268 if "float" in vk_type: 269 if '[' in vk_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic) 270 if cpp: 271 return ("[%i, %i, %i, %i]", '"[" << %s[0] << "," << %s[1] << "," << %s[2] << "," << %s[3] << "]"' % (name, name, name, name)) 272 return ("[%f, %f, %f, %f]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name)) 273 return ("%f", name) 274 if "bool" in vk_type.lower() or 'xcb_randr_crtc_t' in vk_type: 275 return ("%u", name) 276 if True in [t in vk_type.lower() for t in ["int", "flags", "mask", "xcb_window_t"]]: 277 if '[' in vk_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic) 278 if cpp: 279 return ("[%i, %i, %i, %i]", "%s[0] << %s[1] << %s[2] << %s[3]" % (name, name, name, name)) 280 return ("[%i, %i, %i, %i]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name)) 281 if '*' in vk_type: 282 if 'pUserData' == name: 283 return ("%i", "((pUserData == 0) ? 0 : *(pUserData))") 284 if 'const' in vk_type.lower(): 285 return ("%p", "(void*)(%s)" % name) 286 return ("%i", "*(%s)" % name) 287 return ("%i", name) 288 # TODO : This is special-cased as there's only one "format" param currently and it's nice to expand it 289 if "VkFormat" == vk_type: 290 if cpp: 291 return ("%p", "&%s" % name) 292 return ("{%s.channelFormat = %%s, %s.numericFormat = %%s}" % (name, name), "string_VK_COLOR_COMPONENT_FORMAT(%s.channelFormat), string_VK_FORMAT_RANGE_SIZE(%s.numericFormat)" % (name, name)) 293 if output_param: 294 return ("%p", "(void*)*%s" % name) 295 if vk_helper.is_type(vk_type, 'struct') and '*' not in vk_type: 296 return ("%p", "(void*)(&%s)" % name) 297 return ("%p", "(void*)(%s)" % name) 298 299 def _gen_create_msg_callback(self): 300 r_body = [] 301 r_body.append('%s' % self.lineinfo.get()) 302 r_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(') 303 r_body.append(' VkInstance instance,') 304 r_body.append(' const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,') 305 r_body.append(' const VkAllocationCallbacks* pAllocator,') 306 r_body.append(' VkDebugReportCallbackEXT* pCallback)') 307 r_body.append('{') 308 # Switch to this code section for the new per-instance storage and debug callbacks 309 if self.layer_name in ['object_tracker', 'unique_objects']: 310 r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name ) 311 r_body.append(' VkResult result = pInstanceTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);') 312 r_body.append(' if (VK_SUCCESS == result) {') 313 r_body.append(' layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);') 314 r_body.append(' result = layer_create_msg_callback(my_data->report_data,') 315 r_body.append(' pCreateInfo,') 316 r_body.append(' pAllocator,') 317 r_body.append(' pCallback);') 318 r_body.append(' }') 319 r_body.append(' return result;') 320 else: 321 r_body.append(' VkResult result = instance_dispatch_table(instance)->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);') 322 r_body.append(' if (VK_SUCCESS == result) {') 323 r_body.append(' layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);') 324 r_body.append(' result = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pCallback);') 325 r_body.append(' }') 326 r_body.append(' return result;') 327 r_body.append('}') 328 return "\n".join(r_body) 329 330 def _gen_destroy_msg_callback(self): 331 r_body = [] 332 r_body.append('%s' % self.lineinfo.get()) 333 r_body.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback, const VkAllocationCallbacks *pAllocator)') 334 r_body.append('{') 335 # Switch to this code section for the new per-instance storage and debug callbacks 336 if self.layer_name in ['object_tracker', 'unique_objects']: 337 r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name ) 338 else: 339 r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);') 340 r_body.append(' pInstanceTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);') 341 r_body.append(' layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);') 342 r_body.append(' layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);') 343 r_body.append('}') 344 return "\n".join(r_body) 345 346 def _gen_debug_report_msg(self): 347 r_body = [] 348 r_body.append('%s' % self.lineinfo.get()) 349 r_body.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg)') 350 r_body.append('{') 351 # Switch to this code section for the new per-instance storage and debug callbacks 352 if self.layer_name == 'object_tracker': 353 r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name ) 354 else: 355 r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);') 356 r_body.append(' pInstanceTable->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);') 357 r_body.append('}') 358 return "\n".join(r_body) 359 360 def _gen_layer_get_global_extension_props(self, layer="object_tracker"): 361 ggep_body = [] 362 # generated layers do not provide any global extensions 363 ggep_body.append('%s' % self.lineinfo.get()) 364 365 ggep_body.append('') 366 if self.layer_name == 'object_tracker': 367 ggep_body.append('static const VkExtensionProperties instance_extensions[] = {') 368 ggep_body.append(' {') 369 ggep_body.append(' VK_EXT_DEBUG_REPORT_EXTENSION_NAME,') 370 ggep_body.append(' VK_EXT_DEBUG_REPORT_SPEC_VERSION') 371 ggep_body.append(' }') 372 ggep_body.append('};') 373 ggep_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties* pProperties)') 374 ggep_body.append('{') 375 if self.layer_name == 'object_tracker': 376 ggep_body.append(' return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);') 377 else: 378 ggep_body.append(' return util_GetExtensionProperties(0, NULL, pCount, pProperties);') 379 ggep_body.append('}') 380 return "\n".join(ggep_body) 381 382 def _gen_layer_get_global_layer_props(self, layer="object_tracker"): 383 ggep_body = [] 384 layer_name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', layer) 385 layer_name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', layer_name).lower() 386 ggep_body.append('%s' % self.lineinfo.get()) 387 ggep_body.append('static const VkLayerProperties globalLayerProps[] = {') 388 ggep_body.append(' {') 389 if self.layer_name in ['unique_objects']: 390 ggep_body.append(' "VK_LAYER_GOOGLE_%s",' % layer) 391 ggep_body.append(' VK_LAYER_API_VERSION, // specVersion') 392 ggep_body.append(' 1, // implementationVersion') 393 ggep_body.append(' "Google Validation Layer"') 394 else: 395 ggep_body.append(' "VK_LAYER_LUNARG_%s",' % layer) 396 ggep_body.append(' VK_LAYER_API_VERSION, // specVersion') 397 ggep_body.append(' 1, // implementationVersion') 398 ggep_body.append(' "LunarG Validation Layer"') 399 ggep_body.append(' }') 400 ggep_body.append('};') 401 ggep_body.append('') 402 ggep_body.append('%s' % self.lineinfo.get()) 403 ggep_body.append('') 404 ggep_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties* pProperties)') 405 ggep_body.append('{') 406 ggep_body.append(' return util_GetLayerProperties(ARRAY_SIZE(globalLayerProps), globalLayerProps, pCount, pProperties);') 407 ggep_body.append('}') 408 return "\n".join(ggep_body) 409 410 def _gen_layer_get_physical_device_layer_props(self, layer="object_tracker"): 411 gpdlp_body = [] 412 gpdlp_body.append('%s' % self.lineinfo.get()) 413 gpdlp_body.append('static const VkLayerProperties deviceLayerProps[] = {') 414 gpdlp_body.append(' {') 415 if self.layer_name in ['unique_objects']: 416 gpdlp_body.append(' "VK_LAYER_GOOGLE_%s",' % layer) 417 gpdlp_body.append(' VK_LAYER_API_VERSION, // specVersion') 418 gpdlp_body.append(' 1, // implementationVersion') 419 gpdlp_body.append(' "Google Validation Layer"') 420 else: 421 gpdlp_body.append(' "VK_LAYER_LUNARG_%s",' % layer) 422 gpdlp_body.append(' VK_LAYER_API_VERSION, // specVersion') 423 gpdlp_body.append(' 1, // implementationVersion') 424 gpdlp_body.append(' "LunarG Validation Layer"') 425 gpdlp_body.append(' }') 426 gpdlp_body.append('};') 427 gpdlp_body.append('VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties* pProperties)') 428 gpdlp_body.append('{') 429 gpdlp_body.append(' return util_GetLayerProperties(ARRAY_SIZE(deviceLayerProps), deviceLayerProps, pCount, pProperties);') 430 gpdlp_body.append('}') 431 gpdlp_body.append('') 432 return "\n".join(gpdlp_body) 433 434 def _generate_dispatch_entrypoints(self, qual=""): 435 if qual: 436 qual += " " 437 438 funcs = [] 439 intercepted = [] 440 for proto in self.protos: 441 if proto.name == "GetDeviceProcAddr" or proto.name == "GetInstanceProcAddr": 442 continue 443 else: 444 intercept = self.generate_intercept(proto, qual) 445 if intercept is None: 446 # fill in default intercept for certain entrypoints 447 if 'CreateDebugReportCallbackEXT' == proto.name: 448 intercept = self._gen_layer_dbg_create_msg_callback() 449 elif 'DestroyDebugReportCallbackEXT' == proto.name: 450 intercept = self._gen_layer_dbg_destroy_msg_callback() 451 elif 'DebugReportMessageEXT' == proto.name: 452 intercept = self._gen_debug_report_msg() 453 elif 'CreateDevice' == proto.name: 454 funcs.append('/* CreateDevice HERE */') 455 elif 'EnumerateInstanceExtensionProperties' == proto.name: 456 intercept = self._gen_layer_get_global_extension_props(self.layer_name) 457 elif 'EnumerateInstanceLayerProperties' == proto.name: 458 intercept = self._gen_layer_get_global_layer_props(self.layer_name) 459 elif 'EnumerateDeviceLayerProperties' == proto.name: 460 intercept = self._gen_layer_get_physical_device_layer_props(self.layer_name) 461 462 if intercept is not None: 463 funcs.append(intercept) 464 if not "KHR" in proto.name: 465 intercepted.append(proto) 466 467 prefix="vk" 468 lookups = [] 469 for proto in intercepted: 470 lookups.append("if (!strcmp(name, \"%s\"))" % proto.name) 471 lookups.append(" return (PFN_vkVoidFunction) %s%s;" % 472 (prefix, proto.name)) 473 474 # add customized layer_intercept_proc 475 body = [] 476 body.append('%s' % self.lineinfo.get()) 477 body.append("static inline PFN_vkVoidFunction layer_intercept_proc(const char *name)") 478 body.append("{") 479 body.append(generate_get_proc_addr_check("name")) 480 body.append("") 481 body.append(" name += 2;") 482 body.append(" %s" % "\n ".join(lookups)) 483 body.append("") 484 body.append(" return NULL;") 485 body.append("}") 486 # add layer_intercept_instance_proc 487 lookups = [] 488 for proto in self.protos: 489 if not proto_is_global(proto): 490 continue 491 492 if not proto in intercepted: 493 continue 494 if proto.name == "CreateInstance": 495 continue 496 if proto.name == "CreateDevice": 497 continue 498 lookups.append("if (!strcmp(name, \"%s\"))" % proto.name) 499 lookups.append(" return (PFN_vkVoidFunction) %s%s;" % (prefix, proto.name)) 500 501 body.append("static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name)") 502 body.append("{") 503 body.append(generate_get_proc_addr_check("name")) 504 body.append("") 505 body.append(" name += 2;") 506 body.append(" %s" % "\n ".join(lookups)) 507 body.append("") 508 body.append(" return NULL;") 509 body.append("}") 510 511 funcs.append("\n".join(body)) 512 return "\n\n".join(funcs) 513 514 def _generate_extensions(self): 515 exts = [] 516 exts.append('%s' % self.lineinfo.get()) 517 exts.append(self._gen_create_msg_callback()) 518 exts.append(self._gen_destroy_msg_callback()) 519 exts.append(self._gen_debug_report_msg()) 520 return "\n".join(exts) 521 522 def _generate_layer_gpa_function(self, extensions=[], instance_extensions=[]): 523 func_body = [] 524# 525# New style of GPA Functions for the new layer_data/layer_logging changes 526# 527 if self.layer_name in ['object_tracker', 'unique_objects']: 528 func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName)\n" 529 "{\n" 530 " PFN_vkVoidFunction addr;\n" 531 " if (!strcmp(\"vkGetDeviceProcAddr\", funcName)) {\n" 532 " return (PFN_vkVoidFunction) vkGetDeviceProcAddr;\n" 533 " }\n\n" 534 " addr = layer_intercept_proc(funcName);\n" 535 " if (addr)\n" 536 " return addr;\n" 537 " if (device == VK_NULL_HANDLE) {\n" 538 " return NULL;\n" 539 " }\n") 540 if 0 != len(extensions): 541 func_body.append('%s' % self.lineinfo.get()) 542 func_body.append(' layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);') 543 for (ext_enable, ext_list) in extensions: 544 extra_space = "" 545 if 0 != len(ext_enable): 546 func_body.append(' if (my_device_data->%s) {' % ext_enable) 547 extra_space = " " 548 for ext_name in ext_list: 549 func_body.append(' %sif (!strcmp("%s", funcName))\n' 550 ' %sreturn reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, extra_space, ext_name)) 551 if 0 != len(ext_enable): 552 func_body.append(' }\n') 553 func_body.append("\n if (get_dispatch_table(%s_device_table_map, device)->GetDeviceProcAddr == NULL)\n" 554 " return NULL;\n" 555 " return get_dispatch_table(%s_device_table_map, device)->GetDeviceProcAddr(device, funcName);\n" 556 "}\n" % (self.layer_name, self.layer_name)) 557 func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)\n" 558 "{\n" 559 " PFN_vkVoidFunction addr;\n" 560 " if (!strcmp(funcName, \"vkGetInstanceProcAddr\"))\n" 561 " return (PFN_vkVoidFunction) vkGetInstanceProcAddr;\n" 562 " if (!strcmp(funcName, \"vkCreateInstance\"))\n" 563 " return (PFN_vkVoidFunction) vkCreateInstance;\n" 564 " if (!strcmp(funcName, \"vkCreateDevice\"))\n" 565 " return (PFN_vkVoidFunction) vkCreateDevice;\n" 566 " addr = layer_intercept_instance_proc(funcName);\n" 567 " if (addr) {\n" 568 " return addr;" 569 " }\n" 570 " if (instance == VK_NULL_HANDLE) {\n" 571 " return NULL;\n" 572 " }\n" 573 ) 574 575 table_declared = False 576 if 0 != len(instance_extensions): 577 for (ext_enable, ext_list) in instance_extensions: 578 extra_space = "" 579 if 0 != len(ext_enable): 580 if ext_enable == 'msg_callback_get_proc_addr': 581 func_body.append(" layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);\n" 582 " addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);\n" 583 " if (addr) {\n" 584 " return addr;\n" 585 " }\n") 586 else: 587 if table_declared == False: 588 func_body.append(" VkLayerInstanceDispatchTable* pTable = get_dispatch_table(%s_instance_table_map, instance);" % self.layer_name) 589 table_declared = True 590 func_body.append(' if (instanceExtMap.size() != 0 && instanceExtMap[pTable].%s)' % ext_enable) 591 func_body.append(' {') 592 extra_space = " " 593 for ext_name in ext_list: 594 if wsi_name(ext_name): 595 func_body.append('%s' % wsi_ifdef(ext_name)) 596 func_body.append(' %sif (!strcmp("%s", funcName))\n' 597 ' return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name)) 598 if wsi_name(ext_name): 599 func_body.append('%s' % wsi_endif(ext_name)) 600 if 0 != len(ext_enable): 601 func_body.append(' }\n') 602 603 func_body.append(" if (get_dispatch_table(%s_instance_table_map, instance)->GetInstanceProcAddr == NULL) {\n" 604 " return NULL;\n" 605 " }\n" 606 " return get_dispatch_table(%s_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);\n" 607 "}\n" % (self.layer_name, self.layer_name)) 608 return "\n".join(func_body) 609 else: 610 func_body.append('%s' % self.lineinfo.get()) 611 func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName)\n" 612 "{\n" 613 " PFN_vkVoidFunction addr;\n") 614 func_body.append("\n" 615 " loader_platform_thread_once(&initOnce, init%s);\n\n" 616 " if (!strcmp(\"vkGetDeviceProcAddr\", funcName)) {\n" 617 " return (PFN_vkVoidFunction) vkGetDeviceProcAddr;\n" 618 " }\n\n" 619 " addr = layer_intercept_proc(funcName);\n" 620 " if (addr)\n" 621 " return addr;" % self.layer_name) 622 func_body.append(" if (device == VK_NULL_HANDLE) {\n" 623 " return NULL;\n" 624 " }\n") 625 func_body.append('') 626 func_body.append(' VkLayerDispatchTable *pDisp = device_dispatch_table(device);') 627 if 0 != len(extensions): 628 extra_space = "" 629 for (ext_enable, ext_list) in extensions: 630 if 0 != len(ext_enable): 631 func_body.append(' if (deviceExtMap.size() != 0 && deviceExtMap[pDisp].%s)' % ext_enable) 632 func_body.append(' {') 633 extra_space = " " 634 for ext_name in ext_list: 635 func_body.append(' %sif (!strcmp("%s", funcName))\n' 636 ' return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name)) 637 if 0 != len(ext_enable): 638 func_body.append(' }') 639 func_body.append('%s' % self.lineinfo.get()) 640 func_body.append(" {\n" 641 " if (pDisp->GetDeviceProcAddr == NULL)\n" 642 " return NULL;\n" 643 " return pDisp->GetDeviceProcAddr(device, funcName);\n" 644 " }\n" 645 "}\n") 646 func_body.append('%s' % self.lineinfo.get()) 647 func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)\n" 648 "{\n" 649 " PFN_vkVoidFunction addr;\n" 650 " if (!strcmp(funcName, \"vkGetInstanceProcAddr\"))\n" 651 " return (PFN_vkVoidFunction) vkGetInstanceProcAddr;\n" 652 " if (!strcmp(funcName, \"vkCreateInstance\"))\n" 653 " return (PFN_vkVoidFunction) vkCreateInstance;\n" 654 " if (!strcmp(funcName, \"vkCreateDevice\"))\n" 655 " return (PFN_vkVoidFunction) vkCreateDevice;\n" 656 ) 657 func_body.append( 658 " loader_platform_thread_once(&initOnce, init%s);\n\n" 659 " addr = layer_intercept_instance_proc(funcName);\n" 660 " if (addr)\n" 661 " return addr;" % self.layer_name) 662 func_body.append(" if (instance == VK_NULL_HANDLE) {\n" 663 " return NULL;\n" 664 " }\n") 665 func_body.append("") 666 func_body.append(" VkLayerInstanceDispatchTable* pTable = instance_dispatch_table(instance);\n") 667 if 0 != len(instance_extensions): 668 extra_space = "" 669 for (ext_enable, ext_list) in instance_extensions: 670 if 0 != len(ext_enable): 671 if ext_enable == 'msg_callback_get_proc_addr': 672 func_body.append(" layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);\n" 673 " addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);\n" 674 " if (addr) {\n" 675 " return addr;\n" 676 " }\n") 677 else: 678 func_body.append(' if (instanceExtMap.size() != 0 && instanceExtMap[pTable].%s)' % ext_enable) 679 func_body.append(' {') 680 extra_space = " " 681 for ext_name in ext_list: 682 if wsi_name(ext_name): 683 func_body.append('%s' % wsi_ifdef(ext_name)) 684 func_body.append(' %sif (!strcmp("%s", funcName))\n' 685 ' return reinterpret_cast<PFN_vkVoidFunction>(%s);' % (extra_space, ext_name, ext_name)) 686 if wsi_name(ext_name): 687 func_body.append('%s' % wsi_endif(ext_name)) 688 if 0 != len(ext_enable): 689 func_body.append(' }\n') 690 691 func_body.append(" if (pTable->GetInstanceProcAddr == NULL)\n" 692 " return NULL;\n" 693 " return pTable->GetInstanceProcAddr(instance, funcName);\n" 694 "}\n") 695 return "\n".join(func_body) 696 697 698 def _generate_layer_initialization(self, init_opts=False, prefix='vk', lockname=None, condname=None): 699 func_body = ["#include \"vk_dispatch_table_helper.h\""] 700 func_body.append('%s' % self.lineinfo.get()) 701 func_body.append('static void init_%s(layer_data *my_data, const VkAllocationCallbacks *pAllocator)\n' 702 '{\n' % self.layer_name) 703 if init_opts: 704 func_body.append('%s' % self.lineinfo.get()) 705 func_body.append('') 706 func_body.append(' layer_debug_actions(my_data->report_data, my_data->logging_callback, pAllocator, "lunarg_%s");' % self.layer_name) 707 func_body.append('') 708 if lockname is not None: 709 func_body.append('%s' % self.lineinfo.get()) 710 func_body.append(" if (!%sLockInitialized)" % lockname) 711 func_body.append(" {") 712 func_body.append(" // TODO/TBD: Need to delete this mutex sometime. How???") 713 func_body.append(" loader_platform_thread_create_mutex(&%sLock);" % lockname) 714 if condname is not None: 715 func_body.append(" loader_platform_thread_init_cond(&%sCond);" % condname) 716 func_body.append(" %sLockInitialized = 1;" % lockname) 717 func_body.append(" }") 718 func_body.append("}\n") 719 func_body.append('') 720 return "\n".join(func_body) 721 722class ObjectTrackerSubcommand(Subcommand): 723 def generate_header(self): 724 header_txt = [] 725 header_txt.append('%s' % self.lineinfo.get()) 726 header_txt.append('#include <stdio.h>') 727 header_txt.append('#include <stdlib.h>') 728 header_txt.append('#include <string.h>') 729 header_txt.append('#include <inttypes.h>') 730 header_txt.append('') 731 header_txt.append('#include "vulkan/vulkan.h"') 732 header_txt.append('#include "vk_loader_platform.h"') 733 header_txt.append('') 734 header_txt.append('#include <unordered_map>') 735 header_txt.append('using namespace std;') 736 header_txt.append('#include "vulkan/vk_layer.h"') 737 header_txt.append('#include "vk_layer_config.h"') 738 header_txt.append('#include "vk_layer_table.h"') 739 header_txt.append('#include "vk_layer_data.h"') 740 header_txt.append('#include "vk_layer_logging.h"') 741 header_txt.append('') 742# NOTE: The non-autoGenerated code is in the object_tracker.h header file 743 header_txt.append('#include "object_tracker.h"') 744 header_txt.append('') 745 return "\n".join(header_txt) 746 747 def generate_maps(self): 748 maps_txt = [] 749 for o in vulkan.object_type_list: 750 maps_txt.append('unordered_map<uint64_t, OBJTRACK_NODE*> %sMap;' % (o)) 751 return "\n".join(maps_txt) 752 753 def _gather_object_uses(self, obj_list, struct_type, obj_set): 754 # for each member of struct_type 755 # add objs in obj_list to obj_set 756 # call self for structs 757 for m in vk_helper.struct_dict[struct_type]: 758 if vk_helper.struct_dict[struct_type][m]['type'] in obj_list: 759 obj_set.add(vk_helper.struct_dict[struct_type][m]['type']) 760 elif vk_helper.is_type(vk_helper.struct_dict[struct_type][m]['type'], 'struct'): 761 obj_set = obj_set.union(self._gather_object_uses(obj_list, vk_helper.struct_dict[struct_type][m]['type'], obj_set)) 762 return obj_set 763 764 def generate_procs(self): 765 procs_txt = [] 766 # First parse through funcs and gather dict of all objects seen by each call 767 obj_use_dict = {} 768 proto_list = vulkan.core.protos + vulkan.ext_khr_surface.protos + vulkan.ext_khr_surface.protos + vulkan.ext_khr_win32_surface.protos + vulkan.ext_khr_device_swapchain.protos 769 for proto in proto_list: 770 disp_obj = proto.params[0].ty.strip('*').replace('const ', '') 771 if disp_obj in vulkan.object_dispatch_list: 772 if disp_obj not in obj_use_dict: 773 obj_use_dict[disp_obj] = set() 774 for p in proto.params[1:]: 775 base_type = p.ty.strip('*').replace('const ', '') 776 if base_type in vulkan.object_type_list: 777 obj_use_dict[disp_obj].add(base_type) 778 if vk_helper.is_type(base_type, 'struct'): 779 obj_use_dict[disp_obj] = self._gather_object_uses(vulkan.object_type_list, base_type, obj_use_dict[disp_obj]) 780 #for do in obj_use_dict: 781 # print "Disp obj %s has uses for objs: %s" % (do, ', '.join(obj_use_dict[do])) 782 783 for o in vulkan.object_type_list:# vulkan.core.objects: 784 procs_txt.append('%s' % self.lineinfo.get()) 785 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', o) 786 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:] 787 if o in vulkan.object_dispatch_list: 788 procs_txt.append('static void create_%s(%s dispatchable_object, %s vkObj, VkDebugReportObjectTypeEXT objType)' % (name, o, o)) 789 else: 790 procs_txt.append('static void create_%s(VkDevice dispatchable_object, %s vkObj, VkDebugReportObjectTypeEXT objType)' % (name, o)) 791 procs_txt.append('{') 792 procs_txt.append(' log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, objType,(uint64_t)(vkObj), __LINE__, OBJTRACK_NONE, "OBJTRACK",') 793 procs_txt.append(' "OBJ[%llu] : CREATE %s object 0x%" PRIxLEAST64 , object_track_index++, string_VkDebugReportObjectTypeEXT(objType),') 794 procs_txt.append(' (uint64_t)(vkObj));') 795 procs_txt.append('') 796 procs_txt.append(' OBJTRACK_NODE* pNewObjNode = new OBJTRACK_NODE;') 797 procs_txt.append(' pNewObjNode->belongsTo = (uint64_t)dispatchable_object;') 798 procs_txt.append(' pNewObjNode->objType = objType;') 799 procs_txt.append(' pNewObjNode->status = OBJSTATUS_NONE;') 800 procs_txt.append(' pNewObjNode->vkObj = (uint64_t)(vkObj);') 801 procs_txt.append(' %sMap[(uint64_t)vkObj] = pNewObjNode;' % (o)) 802 procs_txt.append(' uint32_t objIndex = objTypeToIndex(objType);') 803 procs_txt.append(' numObjs[objIndex]++;') 804 procs_txt.append(' numTotalObjs++;') 805 procs_txt.append('}') 806 procs_txt.append('') 807 procs_txt.append('%s' % self.lineinfo.get()) 808 if o in vulkan.object_dispatch_list: 809 procs_txt.append('static void destroy_%s(%s dispatchable_object, %s object)' % (name, o, o)) 810 else: 811 procs_txt.append('static void destroy_%s(VkDevice dispatchable_object, %s object)' % (name, o)) 812 procs_txt.append('{') 813 procs_txt.append(' uint64_t object_handle = (uint64_t)(object);') 814 procs_txt.append(' auto it = %sMap.find(object_handle);' % o) 815 procs_txt.append(' if (it != %sMap.end()) {' % o) 816 procs_txt.append(' OBJTRACK_NODE* pNode = it->second;') 817 procs_txt.append(' uint32_t objIndex = objTypeToIndex(pNode->objType);') 818 procs_txt.append(' assert(numTotalObjs > 0);') 819 procs_txt.append(' numTotalObjs--;') 820 procs_txt.append(' assert(numObjs[objIndex] > 0);') 821 procs_txt.append(' numObjs[objIndex]--;') 822 procs_txt.append(' log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_INFORMATION_BIT_EXT, pNode->objType, object_handle, __LINE__, OBJTRACK_NONE, "OBJTRACK",') 823 procs_txt.append(' "OBJ_STAT Destroy %s obj 0x%" PRIxLEAST64 " (%" PRIu64 " total objs remain & %" PRIu64 " %s objs).",') 824 procs_txt.append(' string_VkDebugReportObjectTypeEXT(pNode->objType), (uint64_t)(object), numTotalObjs, numObjs[objIndex],') 825 procs_txt.append(' string_VkDebugReportObjectTypeEXT(pNode->objType));') 826 procs_txt.append(' delete pNode;') 827 procs_txt.append(' %sMap.erase(it);' % (o)) 828 procs_txt.append(' } else {') 829 procs_txt.append(' log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT ) 0, object_handle, __LINE__, OBJTRACK_NONE, "OBJTRACK",') 830 procs_txt.append(' "Unable to remove obj 0x%" PRIxLEAST64 ". Was it created? Has it already been destroyed?",') 831 procs_txt.append(' object_handle);') 832 procs_txt.append(' }') 833 procs_txt.append('}') 834 procs_txt.append('') 835 procs_txt.append('%s' % self.lineinfo.get()) 836 if o in vulkan.object_dispatch_list: 837 procs_txt.append('static VkBool32 set_%s_status(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o, o)) 838 else: 839 procs_txt.append('static VkBool32 set_%s_status(VkDevice dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o)) 840 procs_txt.append('{') 841 procs_txt.append(' if (object != VK_NULL_HANDLE) {') 842 procs_txt.append(' uint64_t object_handle = (uint64_t)(object);') 843 procs_txt.append(' auto it = %sMap.find(object_handle);' % o) 844 procs_txt.append(' if (it != %sMap.end()) {' % o) 845 procs_txt.append(' it->second->status |= status_flag;') 846 procs_txt.append(' }') 847 procs_txt.append(' else {') 848 procs_txt.append(' // If we do not find it print an error') 849 procs_txt.append(' return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT ) 0, object_handle, __LINE__, OBJTRACK_NONE, "OBJTRACK",') 850 procs_txt.append(' "Unable to set status for non-existent object 0x%" PRIxLEAST64 " of %s type",') 851 procs_txt.append(' object_handle, string_VkDebugReportObjectTypeEXT(objType));') 852 procs_txt.append(' }') 853 procs_txt.append(' }') 854 procs_txt.append(' return VK_FALSE;') 855 procs_txt.append('}') 856 procs_txt.append('') 857 procs_txt.append('%s' % self.lineinfo.get()) 858 procs_txt.append('static VkBool32 validate_%s_status(' % (name)) 859 if o in vulkan.object_dispatch_list: 860 procs_txt.append('%s dispatchable_object, %s object,' % (o, o)) 861 else: 862 procs_txt.append('VkDevice dispatchable_object, %s object,' % (o)) 863 procs_txt.append(' VkDebugReportObjectTypeEXT objType,') 864 procs_txt.append(' ObjectStatusFlags status_mask,') 865 procs_txt.append(' ObjectStatusFlags status_flag,') 866 procs_txt.append(' VkFlags msg_flags,') 867 procs_txt.append(' OBJECT_TRACK_ERROR error_code,') 868 procs_txt.append(' const char *fail_msg)') 869 procs_txt.append('{') 870 procs_txt.append(' uint64_t object_handle = (uint64_t)(object);') 871 procs_txt.append(' auto it = %sMap.find(object_handle);' % o) 872 procs_txt.append(' if (it != %sMap.end()) {' % o) 873 procs_txt.append(' OBJTRACK_NODE* pNode = it->second;') 874 procs_txt.append(' if ((pNode->status & status_mask) != status_flag) {') 875 procs_txt.append(' log_msg(mdd(dispatchable_object), msg_flags, pNode->objType, object_handle, __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",') 876 procs_txt.append(' "OBJECT VALIDATION WARNING: %s object 0x%" PRIxLEAST64 ": %s", string_VkDebugReportObjectTypeEXT(objType),') 877 procs_txt.append(' object_handle, fail_msg);') 878 procs_txt.append(' return VK_FALSE;') 879 procs_txt.append(' }') 880 procs_txt.append(' return VK_TRUE;') 881 procs_txt.append(' }') 882 procs_txt.append(' else {') 883 procs_txt.append(' // If we do not find it print an error') 884 procs_txt.append(' log_msg(mdd(dispatchable_object), msg_flags, (VkDebugReportObjectTypeEXT) 0, object_handle, __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",') 885 procs_txt.append(' "Unable to obtain status for non-existent object 0x%" PRIxLEAST64 " of %s type",') 886 procs_txt.append(' object_handle, string_VkDebugReportObjectTypeEXT(objType));') 887 procs_txt.append(' return VK_FALSE;') 888 procs_txt.append(' }') 889 procs_txt.append('}') 890 procs_txt.append('') 891 procs_txt.append('%s' % self.lineinfo.get()) 892 if o in vulkan.object_dispatch_list: 893 procs_txt.append('static VkBool32 reset_%s_status(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o, o)) 894 else: 895 procs_txt.append('static VkBool32 reset_%s_status(VkDevice dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, ObjectStatusFlags status_flag)' % (name, o)) 896 procs_txt.append('{') 897 procs_txt.append(' uint64_t object_handle = (uint64_t)(object);') 898 procs_txt.append(' auto it = %sMap.find(object_handle);' % o) 899 procs_txt.append(' if (it != %sMap.end()) {' % o) 900 procs_txt.append(' it->second->status &= ~status_flag;') 901 procs_txt.append(' }') 902 procs_txt.append(' else {') 903 procs_txt.append(' // If we do not find it print an error') 904 procs_txt.append(' return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, objType, object_handle, __LINE__, OBJTRACK_UNKNOWN_OBJECT, "OBJTRACK",') 905 procs_txt.append(' "Unable to reset status for non-existent object 0x%" PRIxLEAST64 " of %s type",') 906 procs_txt.append(' object_handle, string_VkDebugReportObjectTypeEXT(objType));') 907 procs_txt.append(' }') 908 procs_txt.append(' return VK_FALSE;') 909 procs_txt.append('}') 910 procs_txt.append('') 911 procs_txt.append('%s' % self.lineinfo.get()) 912 # Generate the permutations of validate_* functions where for each 913 # dispatchable object type, we have a corresponding validate_* function 914 # for that object and all non-dispatchable objects that are used in API 915 # calls with that dispatchable object. 916 procs_txt.append('//%s' % str(obj_use_dict)) 917 for do in obj_use_dict: 918 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', do) 919 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:] 920 # First create validate_* func for disp obj 921 procs_txt.append('%s' % self.lineinfo.get()) 922 procs_txt.append('static VkBool32 validate_%s(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, bool null_allowed)' % (name, do, do)) 923 procs_txt.append('{') 924 procs_txt.append(' if (null_allowed && (object == VK_NULL_HANDLE))') 925 procs_txt.append(' return VK_FALSE;') 926 procs_txt.append(' if (%sMap.find((uint64_t)object) == %sMap.end()) {' % (do, do)) 927 procs_txt.append(' return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, objType, (uint64_t)(object), __LINE__, OBJTRACK_INVALID_OBJECT, "OBJTRACK",') 928 procs_txt.append(' "Invalid %s Object 0x%%" PRIx64 ,(uint64_t)(object));' % do) 929 procs_txt.append(' }') 930 procs_txt.append(' return VK_FALSE;') 931 procs_txt.append('}') 932 procs_txt.append('') 933 for o in obj_use_dict[do]: 934 if o == do: # We already generated this case above so skip here 935 continue 936 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', o) 937 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:] 938 procs_txt.append('%s' % self.lineinfo.get()) 939 procs_txt.append('static VkBool32 validate_%s(%s dispatchable_object, %s object, VkDebugReportObjectTypeEXT objType, bool null_allowed)' % (name, do, o)) 940 procs_txt.append('{') 941 procs_txt.append(' if (null_allowed && (object == VK_NULL_HANDLE))') 942 procs_txt.append(' return VK_FALSE;') 943 if o == "VkImage": 944 procs_txt.append(' // We need to validate normal image objects and those from the swapchain') 945 procs_txt.append(' if ((%sMap.find((uint64_t)object) == %sMap.end()) &&' % (o, o)) 946 procs_txt.append(' (swapchainImageMap.find((uint64_t)object) == swapchainImageMap.end())) {') 947 else: 948 procs_txt.append(' if (%sMap.find((uint64_t)object) == %sMap.end()) {' % (o, o)) 949 procs_txt.append(' return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, objType, (uint64_t)(object), __LINE__, OBJTRACK_INVALID_OBJECT, "OBJTRACK",') 950 procs_txt.append(' "Invalid %s Object 0x%%" PRIx64, (uint64_t)(object));' % o) 951 procs_txt.append(' }') 952 procs_txt.append(' return VK_FALSE;') 953 procs_txt.append('}') 954 procs_txt.append('') 955 procs_txt.append('') 956 return "\n".join(procs_txt) 957 958 def generate_destroy_instance(self): 959 gedi_txt = [] 960 gedi_txt.append('%s' % self.lineinfo.get()) 961 gedi_txt.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(') 962 gedi_txt.append('VkInstance instance,') 963 gedi_txt.append('const VkAllocationCallbacks* pAllocator)') 964 gedi_txt.append('{') 965 gedi_txt.append(' loader_platform_thread_lock_mutex(&objLock);') 966 gedi_txt.append(' validate_instance(instance, instance, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, false);') 967 gedi_txt.append('') 968 gedi_txt.append(' destroy_instance(instance, instance);') 969 gedi_txt.append(' // Report any remaining objects in LL') 970 gedi_txt.append('') 971 gedi_txt.append(' for (auto iit = VkDeviceMap.begin(); iit != VkDeviceMap.end();) {') 972 gedi_txt.append(' OBJTRACK_NODE* pNode = iit->second;') 973 gedi_txt.append(' if (pNode->belongsTo == (uint64_t)instance) {') 974 gedi_txt.append(' log_msg(mid(instance), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, pNode->vkObj, __LINE__, OBJTRACK_OBJECT_LEAK, "OBJTRACK",') 975 gedi_txt.append(' "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.", string_VkDebugReportObjectTypeEXT(pNode->objType),') 976 gedi_txt.append(' pNode->vkObj);') 977 for o in vulkan.core.objects: 978 if o in ['VkInstance', 'VkPhysicalDevice', 'VkQueue', 'VkDevice']: 979 continue 980 gedi_txt.append(' for (auto idt = %sMap.begin(); idt != %sMap.end();) {' % (o, o)) 981 gedi_txt.append(' OBJTRACK_NODE* pNode = idt->second;') 982 gedi_txt.append(' if (pNode->belongsTo == iit->first) {') 983 gedi_txt.append(' log_msg(mid(instance), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, pNode->vkObj, __LINE__, OBJTRACK_OBJECT_LEAK, "OBJTRACK",') 984 gedi_txt.append(' "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.", string_VkDebugReportObjectTypeEXT(pNode->objType),') 985 gedi_txt.append(' pNode->vkObj);') 986 gedi_txt.append(' %sMap.erase(idt++);' % o ) 987 gedi_txt.append(' } else {') 988 gedi_txt.append(' ++idt;') 989 gedi_txt.append(' }') 990 gedi_txt.append(' }') 991 gedi_txt.append(' VkDeviceMap.erase(iit++);') 992 gedi_txt.append(' } else {') 993 gedi_txt.append(' ++iit;') 994 gedi_txt.append(' }') 995 gedi_txt.append(' }') 996 gedi_txt.append('') 997 gedi_txt.append(' dispatch_key key = get_dispatch_key(instance);') 998 gedi_txt.append(' VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(object_tracker_instance_table_map, instance);') 999 gedi_txt.append(' pInstanceTable->DestroyInstance(instance, pAllocator);') 1000 gedi_txt.append('') 1001 gedi_txt.append(' layer_data *my_data = get_my_data_ptr(key, layer_data_map);') 1002 gedi_txt.append(' // Clean up logging callback, if any') 1003 gedi_txt.append(' while (my_data->logging_callback.size() > 0) {') 1004 gedi_txt.append(' VkDebugReportCallbackEXT callback = my_data->logging_callback.back();') 1005 gedi_txt.append(' layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);') 1006 gedi_txt.append(' my_data->logging_callback.pop_back();') 1007 gedi_txt.append(' }') 1008 gedi_txt.append('') 1009 gedi_txt.append(' layer_debug_report_destroy_instance(mid(instance));') 1010 gedi_txt.append(' layer_data_map.erase(pInstanceTable);') 1011 gedi_txt.append('') 1012 gedi_txt.append(' instanceExtMap.erase(pInstanceTable);') 1013 gedi_txt.append(' loader_platform_thread_unlock_mutex(&objLock);') 1014 # The loader holds a mutex that protects this from other threads 1015 gedi_txt.append(' object_tracker_instance_table_map.erase(key);') 1016 gedi_txt.append(' if (object_tracker_instance_table_map.empty()) {') 1017 gedi_txt.append(' // Release mutex when destroying last instance.') 1018 gedi_txt.append(' loader_platform_thread_delete_mutex(&objLock);') 1019 gedi_txt.append(' objLockInitialized = 0;') 1020 gedi_txt.append(' }') 1021 gedi_txt.append('}') 1022 gedi_txt.append('') 1023 return "\n".join(gedi_txt) 1024 1025 def generate_destroy_device(self): 1026 gedd_txt = [] 1027 gedd_txt.append('%s' % self.lineinfo.get()) 1028 gedd_txt.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(') 1029 gedd_txt.append('VkDevice device,') 1030 gedd_txt.append('const VkAllocationCallbacks* pAllocator)') 1031 gedd_txt.append('{') 1032 gedd_txt.append(' loader_platform_thread_lock_mutex(&objLock);') 1033 gedd_txt.append(' validate_device(device, device, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, false);') 1034 gedd_txt.append('') 1035 gedd_txt.append(' destroy_device(device, device);') 1036 gedd_txt.append(' // Report any remaining objects associated with this VkDevice object in LL') 1037 for o in vulkan.core.objects: 1038 # DescriptorSets and Command Buffers are destroyed through their pools, not explicitly 1039 if o in ['VkInstance', 'VkPhysicalDevice', 'VkQueue', 'VkDevice', 'VkDescriptorSet', 'VkCommandBuffer']: 1040 continue 1041 gedd_txt.append(' for (auto it = %sMap.begin(); it != %sMap.end();) {' % (o, o)) 1042 gedd_txt.append(' OBJTRACK_NODE* pNode = it->second;') 1043 gedd_txt.append(' if (pNode->belongsTo == (uint64_t)device) {') 1044 gedd_txt.append(' log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, pNode->objType, pNode->vkObj, __LINE__, OBJTRACK_OBJECT_LEAK, "OBJTRACK",') 1045 gedd_txt.append(' "OBJ ERROR : %s object 0x%" PRIxLEAST64 " has not been destroyed.", string_VkDebugReportObjectTypeEXT(pNode->objType),') 1046 gedd_txt.append(' pNode->vkObj);') 1047 gedd_txt.append(' %sMap.erase(it++);' % o ) 1048 gedd_txt.append(' } else {') 1049 gedd_txt.append(' ++it;') 1050 gedd_txt.append(' }') 1051 gedd_txt.append(' }') 1052 gedd_txt.append('') 1053 gedd_txt.append(" // Clean up Queue's MemRef Linked Lists") 1054 gedd_txt.append(' destroyQueueMemRefLists();') 1055 gedd_txt.append('') 1056 gedd_txt.append(' loader_platform_thread_unlock_mutex(&objLock);') 1057 gedd_txt.append('') 1058 gedd_txt.append(' dispatch_key key = get_dispatch_key(device);') 1059 gedd_txt.append(' VkLayerDispatchTable *pDisp = get_dispatch_table(object_tracker_device_table_map, device);') 1060 gedd_txt.append(' pDisp->DestroyDevice(device, pAllocator);') 1061 gedd_txt.append(' object_tracker_device_table_map.erase(key);') 1062 gedd_txt.append('') 1063 gedd_txt.append('}') 1064 gedd_txt.append('') 1065 return "\n".join(gedd_txt) 1066 1067 # Special-case validating some objects -- they may be non-NULL but should 1068 # only be validated upon meeting some condition specified below. 1069 def _dereference_conditionally(self, indent, prefix, type_name, name): 1070 s_code = '' 1071 if type_name == 'pBufferInfo': 1072 s_code += '%sif ((%sdescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||\n' % (indent, prefix) 1073 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||\n' % (indent, prefix) 1074 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||\n' % (indent, prefix) 1075 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) ) {\n' % (indent, prefix) 1076 elif type_name == 'pImageInfo': 1077 s_code += '%sif ((%sdescriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) ||\n' % (indent, prefix) 1078 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||\n' % (indent, prefix) 1079 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||\n' % (indent, prefix) 1080 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||\n' % (indent, prefix) 1081 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ) {\n' % (indent, prefix) 1082 elif type_name == 'pTexelBufferView': 1083 s_code += '%sif ((%sdescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||\n' % (indent, prefix) 1084 s_code += '%s (%sdescriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) ) {\n' % (indent, prefix) 1085 elif name == 'pBeginInfo->pInheritanceInfo': 1086 s_code += '%sOBJTRACK_NODE* pNode = VkCommandBufferMap[(uint64_t)commandBuffer];\n' % (indent) 1087 s_code += '%sif ((%s) && (pNode->status & OBJSTATUS_COMMAND_BUFFER_SECONDARY)) {\n' % (indent, name) 1088 else: 1089 s_code += '%sif (%s) {\n' % (indent, name) 1090 return s_code 1091 1092 def _gen_obj_validate_code(self, struct_uses, obj_type_mapping, func_name, valid_null_dict, param0_name, indent, prefix, array_index): 1093 pre_code = '' 1094 for obj in sorted(struct_uses): 1095 name = obj 1096 array = '' 1097 type_name = '' 1098 if '[' in obj: 1099 (name, array) = obj.split('[') 1100 type_name = name 1101 array = array.strip(']') 1102 if isinstance(struct_uses[obj], dict): 1103 local_prefix = '' 1104 name = '%s%s' % (prefix, name) 1105 ptr_type = False 1106 if 'p' == obj[0]: 1107 ptr_type = True 1108 tmp_pre = self._dereference_conditionally(indent, prefix, type_name, name) 1109 pre_code += tmp_pre 1110 indent += ' ' 1111 if array != '': 1112 idx = 'idx%s' % str(array_index) 1113 array_index += 1 1114 pre_code += '%s\n' % self.lineinfo.get() 1115 pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx) 1116 indent += ' ' 1117 local_prefix = '%s[%s].' % (name, idx) 1118 elif ptr_type: 1119 local_prefix = '%s->' % (name) 1120 else: 1121 local_prefix = '%s.' % (name) 1122 tmp_pre = self._gen_obj_validate_code(struct_uses[obj], obj_type_mapping, func_name, valid_null_dict, param0_name, indent, local_prefix, array_index) 1123 pre_code += tmp_pre 1124 if array != '': 1125 indent = indent[4:] 1126 pre_code += '%s}\n' % (indent) 1127 if ptr_type: 1128 indent = indent[4:] 1129 pre_code += '%s}\n' % (indent) 1130 else: 1131 ptype = struct_uses[obj] 1132 dbg_obj_type = obj_type_mapping[ptype] 1133 fname = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', ptype) 1134 fname = re.sub('([a-z0-9])([A-Z])', r'\1_\2', fname).lower()[3:] 1135 full_name = '%s%s' % (prefix, name) 1136 null_obj_ok = 'false' 1137 # If a valid null param is defined for this func and we have a match, allow NULL 1138 if func_name in valid_null_dict and True in [name in pn for pn in valid_null_dict[func_name]]: 1139 null_obj_ok = 'true' 1140 if (array_index > 0) or '' != array: 1141 tmp_pre = self._dereference_conditionally(indent, prefix, type_name, full_name) 1142 pre_code += tmp_pre 1143 indent += ' ' 1144 if array != '': 1145 idx = 'idx%s' % str(array_index) 1146 array_index += 1 1147 pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx) 1148 indent += ' ' 1149 full_name = '%s[%s]' % (full_name, idx) 1150 pre_code += '%s\n' % self.lineinfo.get() 1151 pre_code += '%sskipCall |= validate_%s(%s, %s, %s, %s);\n' %(indent, fname, param0_name, full_name, dbg_obj_type, null_obj_ok) 1152 if array != '': 1153 indent = indent[4:] 1154 pre_code += '%s}\n' % (indent) 1155 indent = indent[4:] 1156 pre_code += '%s}\n' % (indent) 1157 else: 1158 pre_code += '%s\n' % self.lineinfo.get() 1159 pre_code += '%sskipCall |= validate_%s(%s, %s, %s, %s);\n' %(indent, fname, param0_name, full_name, dbg_obj_type, null_obj_ok) 1160 return pre_code 1161 1162 def generate_intercept(self, proto, qual): 1163 if proto.name in [ 'CreateDebugReportCallbackEXT', 'EnumerateInstanceLayerProperties', 'EnumerateInstanceExtensionProperties','EnumerateDeviceLayerProperties', 'EnumerateDeviceExtensionProperties' ]: 1164 # use default version 1165 return None 1166 1167 # Create map of object names to object type enums of the form VkName : VkObjectTypeName 1168 obj_type_mapping = {base_t : base_t.replace("Vk", "VkDebugReportObjectType") for base_t in vulkan.object_type_list} 1169 # Convert object type enum names from UpperCamelCase to UPPER_CASE_WITH_UNDERSCORES 1170 for objectName, objectTypeEnum in obj_type_mapping.items(): 1171 obj_type_mapping[objectName] = ucc_to_U_C_C(objectTypeEnum) + '_EXT'; 1172 # Command Buffer Object doesn't follow the rule. 1173 obj_type_mapping['VkCommandBuffer'] = "VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT" 1174 obj_type_mapping['VkShaderModule'] = "VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT" 1175 1176 explicit_object_tracker_functions = [ 1177 "CreateInstance", 1178 "EnumeratePhysicalDevices", 1179 "GetPhysicalDeviceQueueFamilyProperties", 1180 "CreateDevice", 1181 "GetDeviceQueue", 1182 "QueueBindSparse", 1183 "AllocateDescriptorSets", 1184 "FreeDescriptorSets", 1185 "CreateGraphicsPipelines", 1186 "CreateComputePipelines", 1187 "AllocateCommandBuffers", 1188 "FreeCommandBuffers", 1189 "DestroyDescriptorPool", 1190 "DestroyCommandPool", 1191 "MapMemory", 1192 "UnmapMemory", 1193 "FreeMemory", 1194 "DestroySwapchainKHR", 1195 "GetSwapchainImagesKHR" 1196 ] 1197 decl = proto.c_func(prefix="vk", attr="VKAPI") 1198 param0_name = proto.params[0].name 1199 using_line = '' 1200 create_line = '' 1201 destroy_line = '' 1202 # Dict below tracks params that are vk objects. Dict is "loop count"->["params w/ that loop count"] where '0' is params that aren't in an array 1203 # TODO : Should integrate slightly better code for this purpose from unique_objects layer 1204 loop_params = defaultdict(list) # Dict uses loop count as key to make final code generation cleaner so params shared in single loop where needed 1205 loop_types = defaultdict(list) 1206 # TODO : For now skipping objs that can be NULL. Really should check these and have special case that allows them to be NULL 1207 # or better yet, these should be encoded into an API json definition and we generate checks from there 1208 # Until then, this is a dict where each func name is a list of object params that can be null (so don't need to be validated) 1209 # param names may be directly passed to the function, or may be a field in a struct param 1210 valid_null_object_names = {'CreateGraphicsPipelines' : ['basePipelineHandle'], 1211 'CreateComputePipelines' : ['basePipelineHandle'], 1212 'BeginCommandBuffer' : ['renderPass', 'framebuffer'], 1213 'QueueSubmit' : ['fence'], 1214 'AcquireNextImageKHR' : ['fence', 'semaphore' ], 1215 'UpdateDescriptorSets' : ['pTexelBufferView'], 1216 'CreateSwapchainKHR' : ['oldSwapchain'], 1217 } 1218 param_count = 'NONE' # keep track of arrays passed directly into API functions 1219 for p in proto.params: 1220 base_type = p.ty.replace('const ', '').strip('*') 1221 if 'count' in p.name.lower(): 1222 param_count = p.name 1223 if base_type in vulkan.core.objects: 1224 # This is an object to potentially check for validity. First see if it's an array 1225 if '*' in p.ty and 'const' in p.ty and param_count != 'NONE': 1226 loop_params[param_count].append(p.name) 1227 loop_types[param_count].append(str(p.ty[6:-1])) 1228 # Not an array, check for just a base Object that's not in exceptions 1229 elif '*' not in p.ty and (proto.name not in valid_null_object_names or p.name not in valid_null_object_names[proto.name]): 1230 loop_params[0].append(p.name) 1231 loop_types[0].append(str(p.ty)) 1232 elif vk_helper.is_type(base_type, 'struct'): 1233 struct_type = base_type 1234 if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict: 1235 struct_type = vk_helper.typedef_rev_dict[struct_type] 1236 # Parse elements of this struct param to identify objects and/or arrays of objects 1237 for m in sorted(vk_helper.struct_dict[struct_type]): 1238 if vk_helper.struct_dict[struct_type][m]['type'] in vulkan.core.objects and vk_helper.struct_dict[struct_type][m]['type'] not in ['VkPhysicalDevice', 'VkQueue', 'VkFence', 'VkImage', 'VkDeviceMemory']: 1239 if proto.name not in valid_null_object_names or vk_helper.struct_dict[struct_type][m]['name'] not in valid_null_object_names[proto.name]: 1240 # This is not great, but gets the job done for now, but If we have a count and this param is a ptr w/ 1241 # last letter 's' OR non-'count' string of count is in the param name, then this is a dynamically sized array param 1242 param_array = False 1243 if param_count != 'NONE': 1244 if '*' in p.ty: 1245 if 's' == p.name[-1] or param_count.lower().replace('count', '') in p.name.lower(): 1246 param_array = True 1247 if param_array: 1248 param_name = '%s[i].%s' % (p.name, vk_helper.struct_dict[struct_type][m]['name']) 1249 else: 1250 param_name = '%s->%s' % (p.name, vk_helper.struct_dict[struct_type][m]['name']) 1251 if vk_helper.struct_dict[struct_type][m]['dyn_array']: 1252 if param_count != 'NONE': # this will be a double-embedded loop, use comma delineated 'count,name' for param_name 1253 loop_count = '%s[i].%s' % (p.name, vk_helper.struct_dict[struct_type][m]['array_size']) 1254 loop_params[param_count].append('%s,%s' % (loop_count, param_name)) 1255 loop_types[param_count].append('%s' % (vk_helper.struct_dict[struct_type][m]['type'])) 1256 else: 1257 loop_count = '%s->%s' % (p.name, vk_helper.struct_dict[struct_type][m]['array_size']) 1258 loop_params[loop_count].append(param_name) 1259 loop_types[loop_count].append('%s' % (vk_helper.struct_dict[struct_type][m]['type'])) 1260 else: 1261 if '[' in param_name: # dynamic array param, set size 1262 loop_params[param_count].append(param_name) 1263 loop_types[param_count].append('%s' % (vk_helper.struct_dict[struct_type][m]['type'])) 1264 else: 1265 loop_params[0].append(param_name) 1266 loop_types[0].append('%s' % (vk_helper.struct_dict[struct_type][m]['type'])) 1267 last_param_index = None 1268 create_func = False 1269 if True in [create_txt in proto.name for create_txt in ['Create', 'Allocate']]: 1270 create_func = True 1271 last_param_index = -1 # For create funcs don't validate last object 1272 (struct_uses, local_decls) = get_object_uses(vulkan.object_type_list, proto.params[:last_param_index]) 1273 funcs = [] 1274 mutex_unlock = False 1275 funcs.append('%s\n' % self.lineinfo.get()) 1276 if proto.name in explicit_object_tracker_functions: 1277 funcs.append('%s%s\n' 1278 '{\n' 1279 ' return explicit_%s;\n' 1280 '}' % (qual, decl, proto.c_call())) 1281 return "".join(funcs) 1282 # Temporarily prevent DestroySurface call from being generated until WSI layer support is fleshed out 1283 elif 'DestroyInstance' in proto.name or 'DestroyDevice' in proto.name: 1284 return "" 1285 else: 1286 if create_func: 1287 typ = proto.params[-1].ty.strip('*').replace('const ', ''); 1288 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', typ) 1289 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:] 1290 create_line = ' loader_platform_thread_lock_mutex(&objLock);\n' 1291 create_line += ' if (result == VK_SUCCESS) {\n' 1292 create_line += ' create_%s(%s, *%s, %s);\n' % (name, param0_name, proto.params[-1].name, obj_type_mapping[typ]) 1293 create_line += ' }\n' 1294 create_line += ' loader_platform_thread_unlock_mutex(&objLock);\n' 1295 if 'FreeCommandBuffers' in proto.name: 1296 typ = proto.params[-1].ty.strip('*').replace('const ', ''); 1297 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', typ) 1298 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:] 1299 funcs.append('%s\n' % self.lineinfo.get()) 1300 destroy_line = ' loader_platform_thread_lock_mutex(&objLock);\n' 1301 destroy_line += ' for (uint32_t i = 0; i < commandBufferCount; i++) {\n' 1302 destroy_line += ' destroy_%s(%s[i], %s[i]);\n' % (name, proto.params[-1].name, proto.params[-1].name) 1303 destroy_line += ' }\n' 1304 destroy_line += ' loader_platform_thread_unlock_mutex(&objLock);\n' 1305 if 'Destroy' in proto.name: 1306 typ = proto.params[-2].ty.strip('*').replace('const ', ''); 1307 name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', typ) 1308 name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()[3:] 1309 funcs.append('%s\n' % self.lineinfo.get()) 1310 destroy_line = ' loader_platform_thread_lock_mutex(&objLock);\n' 1311 destroy_line += ' destroy_%s(%s, %s);\n' % (name, param0_name, proto.params[-2].name) 1312 destroy_line += ' loader_platform_thread_unlock_mutex(&objLock);\n' 1313 indent = ' ' 1314 if len(struct_uses) > 0: 1315 using_line += '%sVkBool32 skipCall = VK_FALSE;\n' % (indent) 1316 if not mutex_unlock: 1317 using_line += '%sloader_platform_thread_lock_mutex(&objLock);\n' % (indent) 1318 mutex_unlock = True 1319 using_line += '// objects to validate: %s\n' % str(struct_uses) 1320 using_line += self._gen_obj_validate_code(struct_uses, obj_type_mapping, proto.name, valid_null_object_names, param0_name, ' ', '', 0) 1321 if mutex_unlock: 1322 using_line += '%sloader_platform_thread_unlock_mutex(&objLock);\n' % (indent) 1323 if len(struct_uses) > 0: 1324 using_line += ' if (skipCall)\n' 1325 if proto.ret != "void": 1326 using_line += ' return VK_ERROR_VALIDATION_FAILED_EXT;\n' 1327 else: 1328 using_line += ' return;\n' 1329 ret_val = '' 1330 stmt = '' 1331 if proto.ret != "void": 1332 ret_val = "%s result = " % proto.ret 1333 stmt = " return result;\n" 1334 1335 dispatch_param = proto.params[0].name 1336 if 'CreateInstance' in proto.name: 1337 dispatch_param = '*' + proto.params[1].name 1338 1339 # Must use 'instance' table for these APIs, 'device' table otherwise 1340 table_type = "" 1341 if proto_is_global(proto): 1342 table_type = "instance" 1343 else: 1344 table_type = "device" 1345 if wsi_name(proto.name): 1346 funcs.append('%s' % wsi_ifdef(proto.name)) 1347 funcs.append('%s%s\n' 1348 '{\n' 1349 '%s' 1350 '%s' 1351 ' %sget_dispatch_table(object_tracker_%s_table_map, %s)->%s;\n' 1352 '%s' 1353 '%s' 1354 '}' % (qual, decl, using_line, destroy_line, ret_val, table_type, dispatch_param, proto.c_call(), create_line, stmt)) 1355 if wsi_name(proto.name): 1356 funcs.append('%s' % wsi_endif(proto.name)) 1357 return "\n\n".join(funcs) 1358 1359 def generate_body(self): 1360 self.layer_name = "object_tracker" 1361 extensions=[('wsi_enabled', 1362 ['vkCreateSwapchainKHR', 1363 'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR', 1364 'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])] 1365 if self.wsi == 'Win32': 1366 instance_extensions=[('msg_callback_get_proc_addr', []), 1367 ('wsi_enabled', 1368 ['vkDestroySurfaceKHR', 1369 'vkGetPhysicalDeviceSurfaceSupportKHR', 1370 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 1371 'vkGetPhysicalDeviceSurfaceFormatsKHR', 1372 'vkGetPhysicalDeviceSurfacePresentModesKHR', 1373 'vkCreateWin32SurfaceKHR', 1374 'vkGetPhysicalDeviceWin32PresentationSupportKHR'])] 1375 elif self.wsi == 'Android': 1376 instance_extensions=[('msg_callback_get_proc_addr', []), 1377 ('wsi_enabled', 1378 ['vkDestroySurfaceKHR', 1379 'vkGetPhysicalDeviceSurfaceSupportKHR', 1380 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 1381 'vkGetPhysicalDeviceSurfaceFormatsKHR', 1382 'vkGetPhysicalDeviceSurfacePresentModesKHR', 1383 'vkCreateAndroidSurfaceKHR'])] 1384 elif self.wsi == 'Xcb' or self.wsi == 'Xlib' or self.wsi == 'Wayland' or self.wsi == 'Mir': 1385 instance_extensions=[('msg_callback_get_proc_addr', []), 1386 ('wsi_enabled', 1387 ['vkDestroySurfaceKHR', 1388 'vkGetPhysicalDeviceSurfaceSupportKHR', 1389 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 1390 'vkGetPhysicalDeviceSurfaceFormatsKHR', 1391 'vkGetPhysicalDeviceSurfacePresentModesKHR', 1392 'vkCreateXcbSurfaceKHR', 1393 'vkGetPhysicalDeviceXcbPresentationSupportKHR', 1394 'vkCreateXlibSurfaceKHR', 1395 'vkGetPhysicalDeviceXlibPresentationSupportKHR', 1396 'vkCreateWaylandSurfaceKHR', 1397 'vkGetPhysicalDeviceWaylandPresentationSupportKHR', 1398 'vkCreateMirSurfaceKHR', 1399 'vkGetPhysicalDeviceMirPresentationSupportKHR'])] 1400 else: 1401 print('Error: Undefined DisplayServer') 1402 instance_extensions=[] 1403 1404 body = [self.generate_maps(), 1405 self.generate_procs(), 1406 self.generate_destroy_instance(), 1407 self.generate_destroy_device(), 1408 self._generate_dispatch_entrypoints("VK_LAYER_EXPORT"), 1409 self._generate_extensions(), 1410 self._generate_layer_gpa_function(extensions, 1411 instance_extensions)] 1412 return "\n\n".join(body) 1413 1414class UniqueObjectsSubcommand(Subcommand): 1415 def generate_header(self): 1416 header_txt = [] 1417 header_txt.append('%s' % self.lineinfo.get()) 1418 header_txt.append('#include "unique_objects.h"') 1419 return "\n".join(header_txt) 1420 1421 # Generate UniqueObjects code for given struct_uses dict of objects that need to be unwrapped 1422 # vector_name_set is used to make sure we don't replicate vector names 1423 # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct 1424 # TODO : Comment this code 1425 def _gen_obj_code(self, struct_uses, param_type, indent, prefix, array_index, vector_name_set, first_level_param): 1426 decls = '' 1427 pre_code = '' 1428 post_code = '' 1429 for obj in sorted(struct_uses): 1430 name = obj 1431 array = '' 1432 if '[' in obj: 1433 (name, array) = obj.split('[') 1434 array = array.strip(']') 1435 ptr_type = False 1436 if 'p' == obj[0] and obj[1] != obj[1].lower(): # TODO : Not idea way to determine ptr 1437 ptr_type = True 1438 if isinstance(struct_uses[obj], dict): 1439 local_prefix = '' 1440 name = '%s%s' % (prefix, name) 1441 if ptr_type: 1442 if first_level_param and name in param_type: 1443 pre_code += '%sif (%s) {\n' % (indent, name) 1444 else: # shadow ptr will have been initialized at this point so check it vs. source ptr 1445 pre_code += '%sif (local_%s) {\n' % (indent, name) 1446 indent += ' ' 1447 if array != '': 1448 idx = 'idx%s' % str(array_index) 1449 array_index += 1 1450 if first_level_param and name in param_type: 1451 pre_code += '%slocal_%s = new safe_%s[%s];\n' % (indent, name, param_type[name].strip('*'), array) 1452 post_code += ' if (local_%s)\n' % (name) 1453 post_code += ' delete[] local_%s;\n' % (name) 1454 pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx) 1455 indent += ' ' 1456 if first_level_param: 1457 pre_code += '%slocal_%s[%s].initialize(&%s[%s]);\n' % (indent, name, idx, name, idx) 1458 local_prefix = '%s[%s].' % (name, idx) 1459 elif ptr_type: 1460 if first_level_param and name in param_type: 1461 pre_code += '%slocal_%s = new safe_%s(%s);\n' % (indent, name, param_type[name].strip('*'), name) 1462 post_code += ' if (local_%s)\n' % (name) 1463 post_code += ' delete local_%s;\n' % (name) 1464 local_prefix = '%s->' % (name) 1465 else: 1466 local_prefix = '%s.' % (name) 1467 assert isinstance(decls, object) 1468 (tmp_decl, tmp_pre, tmp_post) = self._gen_obj_code(struct_uses[obj], param_type, indent, local_prefix, array_index, vector_name_set, False) 1469 decls += tmp_decl 1470 pre_code += tmp_pre 1471 post_code += tmp_post 1472 if array != '': 1473 indent = indent[4:] 1474 pre_code += '%s}\n' % (indent) 1475 if ptr_type: 1476 indent = indent[4:] 1477 pre_code += '%s}\n' % (indent) 1478 else: 1479 if (array_index > 0) or array != '': # TODO : This is not ideal, really want to know if we're anywhere under an array 1480 if first_level_param: 1481 pre_code += '%s%s* local_%s = NULL;\n' % (indent, struct_uses[obj], name) 1482 if array != '' and not first_level_param: # ptrs under structs will have been initialized so use local_* 1483 pre_code += '%sif (local_%s%s) {\n' %(indent, prefix, name) 1484 else: 1485 pre_code += '%sif (%s%s) {\n' %(indent, prefix, name) 1486 indent += ' ' 1487 if array != '': 1488 idx = 'idx%s' % str(array_index) 1489 array_index += 1 1490 if first_level_param: 1491 pre_code += '%slocal_%s = new %s[%s];\n' % (indent, name, struct_uses[obj], array) 1492 post_code += ' if (local_%s)\n' % (name) 1493 post_code += ' delete[] local_%s;\n' % (name) 1494 pre_code += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, idx, idx, prefix, array, idx) 1495 indent += ' ' 1496 name = '%s[%s]' % (name, idx) 1497 pName = 'p%s' % (struct_uses[obj][2:]) 1498 if name not in vector_name_set: 1499 vector_name_set.add(name) 1500 pre_code += '%slocal_%s%s = (%s)((VkUniqueObject*)%s%s)->actualObject;\n' % (indent, prefix, name, struct_uses[obj], prefix, name) 1501 if array != '': 1502 indent = indent[4:] 1503 pre_code += '%s}\n' % (indent) 1504 indent = indent[4:] 1505 pre_code += '%s}\n' % (indent) 1506 else: 1507 pre_code += '%s\n' % (self.lineinfo.get()) 1508 pre_code += '%sif (%s%s) {\n' %(indent, prefix, name) 1509 indent += ' ' 1510 deref_txt = '&' 1511 if ptr_type: 1512 deref_txt = '' 1513 if '->' in prefix: # need to update local struct 1514 pre_code += '%slocal_%s%s = (%s)((VkUniqueObject*)%s%s)->actualObject;\n' % (indent, prefix, name, struct_uses[obj], prefix, name) 1515 else: 1516 pre_code += '%s%s* p%s = (%s*)%s%s%s;\n' % (indent, struct_uses[obj], name, struct_uses[obj], deref_txt, prefix, name) 1517 pre_code += '%s*p%s = (%s)((VkUniqueObject*)%s%s)->actualObject;\n' % (indent, name, struct_uses[obj], prefix, name) 1518 indent = indent[4:] 1519 pre_code += '%s}\n' % (indent) 1520 return decls, pre_code, post_code 1521 1522 def generate_intercept(self, proto, qual): 1523 create_func = False 1524 destroy_func = False 1525 last_param_index = None #typcially we look at all params for ndos 1526 pre_call_txt = '' # code prior to calling down chain such as unwrap uses of ndos 1527 post_call_txt = '' # code following call down chain such to wrap newly created ndos, or destroy local wrap struct 1528 funcs = [] 1529 indent = ' ' # indent level for generated code 1530 decl = proto.c_func(prefix="vk", attr="VKAPI") 1531 # A few API cases that are manual code 1532 # TODO : Special case Create*Pipelines funcs to handle creating multiple unique objects 1533 explicit_object_tracker_functions = ['GetSwapchainImagesKHR', 1534 'CreateInstance', 1535 'CreateDevice', 1536 'CreateComputePipelines', 1537 'CreateGraphicsPipelines' 1538 ] 1539 # TODO : This is hacky, need to make this a more general-purpose solution for all layers 1540 ifdef_dict = {'CreateXcbSurfaceKHR': 'VK_USE_PLATFORM_XCB_KHR', 1541 'CreateAndroidSurfaceKHR': 'VK_USE_PLATFORM_ANDROID_KHR', 1542 'CreateWin32SurfaceKHR': 'VK_USE_PLATFORM_WIN32_KHR'} 1543 # Give special treatment to create functions that return multiple new objects 1544 # This dict stores array name and size of array 1545 custom_create_dict = {'pDescriptorSets' : 'pAllocateInfo->descriptorSetCount'} 1546 pre_call_txt += '%s\n' % (self.lineinfo.get()) 1547 if proto.name in explicit_object_tracker_functions: 1548 funcs.append('%s%s\n' 1549 '{\n' 1550 ' return explicit_%s;\n' 1551 '}' % (qual, decl, proto.c_call())) 1552 return "".join(funcs) 1553 if True in [create_txt in proto.name for create_txt in ['Create', 'Allocate']]: 1554 create_func = True 1555 last_param_index = -1 # For create funcs don't care if last param is ndo 1556 if True in [destroy_txt in proto.name for destroy_txt in ['Destroy', 'Free']]: 1557 destroy_obj_type = proto.params[-2].ty 1558 if destroy_obj_type in vulkan.object_non_dispatch_list: 1559 destroy_func = True 1560 1561 # First thing we need to do is gather uses of non-dispatchable-objects (ndos) 1562 (struct_uses, local_decls) = get_object_uses(vulkan.object_non_dispatch_list, proto.params[1:last_param_index]) 1563 1564 if len(struct_uses) > 0: 1565 pre_call_txt += '// STRUCT USES:%s\n' % struct_uses 1566 if len(local_decls) > 0: 1567 pre_call_txt += '//LOCAL DECLS:%s\n' % local_decls 1568 if destroy_func: # only one object 1569 for del_obj in struct_uses: 1570 pre_call_txt += '%s%s local_%s = %s;\n' % (indent, struct_uses[del_obj], del_obj, del_obj) 1571 (pre_decl, pre_code, post_code) = self._gen_obj_code(struct_uses, local_decls, ' ', '', 0, set(), True) 1572 # This is a bit hacky but works for now. Need to decl local versions of top-level structs 1573 for ld in local_decls: 1574 init_null_txt = 'NULL'; 1575 if '*' not in local_decls[ld]: 1576 init_null_txt = '{}'; 1577 if local_decls[ld].strip('*') not in vulkan.object_non_dispatch_list: 1578 pre_decl += ' safe_%s local_%s = %s;\n' % (local_decls[ld], ld, init_null_txt) 1579 pre_call_txt += '%s%s' % (pre_decl, pre_code) 1580 post_call_txt += '%s' % (post_code) 1581 elif create_func: 1582 base_type = proto.params[-1].ty.replace('const ', '').strip('*') 1583 if base_type not in vulkan.object_non_dispatch_list: 1584 return None 1585 else: 1586 return None 1587 1588 ret_val = '' 1589 ret_stmt = '' 1590 if proto.ret != "void": 1591 ret_val = "%s result = " % proto.ret 1592 ret_stmt = " return result;\n" 1593 dispatch_param = proto.params[0].name 1594 if 'CreateInstance' in proto.name: 1595 dispatch_param = '*' + proto.params[1].name 1596 if create_func: 1597 obj_type = proto.params[-1].ty.strip('*') 1598 obj_name = proto.params[-1].name 1599 if obj_type in vulkan.object_non_dispatch_list: 1600 local_name = "unique%s" % obj_type[2:] 1601 post_call_txt += '%sif (VK_SUCCESS == result) {\n' % (indent) 1602 indent += ' ' 1603 if obj_name in custom_create_dict: 1604 post_call_txt += '%s\n' % (self.lineinfo.get()) 1605 local_name = '%ss' % (local_name) # add 's' to end for vector of many 1606 post_call_txt += '%sstd::vector<VkUniqueObject*> %s = {};\n' % (indent, local_name) 1607 post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, custom_create_dict[obj_name]) 1608 indent += ' ' 1609 post_call_txt += '%s%s.push_back(new VkUniqueObject());\n' % (indent, local_name) 1610 post_call_txt += '%s%s[i]->actualObject = (uint64_t)%s[i];\n' % (indent, local_name, obj_name) 1611 post_call_txt += '%s%s[i] = (%s)%s[i];\n' % (indent, obj_name, obj_type, local_name) 1612 indent = indent[4:] 1613 post_call_txt += '%s}\n' % (indent) 1614 else: 1615 post_call_txt += '%s\n' % (self.lineinfo.get()) 1616 post_call_txt += '%sVkUniqueObject* %s = new VkUniqueObject();\n' % (indent, local_name) 1617 post_call_txt += '%s%s->actualObject = (uint64_t)*%s;\n' % (indent, local_name, obj_name) 1618 post_call_txt += '%s*%s = (%s)%s;\n' % (indent, obj_name, obj_type, local_name) 1619 indent = indent[4:] 1620 post_call_txt += '%s}\n' % (indent) 1621 elif destroy_func: 1622 del_obj = proto.params[-2].name 1623 if 'count' in del_obj.lower(): 1624 post_call_txt += '%s\n' % (self.lineinfo.get()) 1625 post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, del_obj) 1626 del_obj = proto.params[-1].name 1627 indent += ' ' 1628 post_call_txt += '%sdelete (VkUniqueObject*)%s[i];\n' % (indent, del_obj) 1629 indent = indent[4:] 1630 post_call_txt += '%s}\n' % (indent) 1631 else: 1632 post_call_txt += '%s\n' % (self.lineinfo.get()) 1633 post_call_txt = '%sdelete (VkUniqueObject*)local_%s;\n' % (indent, proto.params[-2].name) 1634 1635 call_sig = proto.c_call() 1636 # Replace default params with any custom local params 1637 for ld in local_decls: 1638 call_sig = call_sig.replace(ld, '(const %s)local_%s' % (local_decls[ld], ld)) 1639 if proto_is_global(proto): 1640 table_type = "instance" 1641 else: 1642 table_type = "device" 1643 pre_call_txt += '%s\n' % (self.lineinfo.get()) 1644 open_ifdef = '' 1645 close_ifdef = '' 1646 if proto.name in ifdef_dict: 1647 open_ifdef = '#ifdef %s\n' % (ifdef_dict[proto.name]) 1648 close_ifdef = '#endif\n' 1649 funcs.append('%s' 1650 '%s%s\n' 1651 '{\n' 1652 '%s' 1653 ' %sget_dispatch_table(unique_objects_%s_table_map, %s)->%s;\n' 1654 '%s' 1655 '%s' 1656 '}\n' 1657 '%s' % (open_ifdef, qual, decl, pre_call_txt, ret_val, table_type, dispatch_param, call_sig, post_call_txt, ret_stmt, close_ifdef)) 1658 return "\n\n".join(funcs) 1659 1660 def generate_body(self): 1661 self.layer_name = "unique_objects" 1662 extensions=[('wsi_enabled', 1663 ['vkCreateSwapchainKHR', 1664 'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR', 1665 'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])] 1666 if self.wsi == 'Win32': 1667 instance_extensions=[('wsi_enabled', 1668 ['vkDestroySurfaceKHR', 1669 'vkGetPhysicalDeviceSurfaceSupportKHR', 1670 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 1671 'vkGetPhysicalDeviceSurfaceFormatsKHR', 1672 'vkGetPhysicalDeviceSurfacePresentModesKHR', 1673 'vkCreateWin32SurfaceKHR' 1674 ])] 1675 elif self.wsi == 'Android': 1676 instance_extensions=[('wsi_enabled', 1677 ['vkDestroySurfaceKHR', 1678 'vkGetPhysicalDeviceSurfaceSupportKHR', 1679 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 1680 'vkGetPhysicalDeviceSurfaceFormatsKHR', 1681 'vkGetPhysicalDeviceSurfacePresentModesKHR', 1682 'vkCreateAndroidSurfaceKHR'])] 1683 elif self.wsi == 'Xcb' or self.wsi == 'Xlib' or self.wsi == 'Wayland' or self.wsi == 'Mir': 1684 instance_extensions=[('wsi_enabled', 1685 ['vkDestroySurfaceKHR', 1686 'vkGetPhysicalDeviceSurfaceSupportKHR', 1687 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 1688 'vkGetPhysicalDeviceSurfaceFormatsKHR', 1689 'vkGetPhysicalDeviceSurfacePresentModesKHR', 1690 'vkCreateXcbSurfaceKHR', 1691 'vkCreateXlibSurfaceKHR', 1692 'vkCreateWaylandSurfaceKHR', 1693 'vkCreateMirSurfaceKHR' 1694 ])] 1695 else: 1696 print('Error: Undefined DisplayServer') 1697 instance_extensions=[] 1698 1699 body = [self._generate_dispatch_entrypoints("VK_LAYER_EXPORT"), 1700 self._generate_layer_gpa_function(extensions, 1701 instance_extensions)] 1702 return "\n\n".join(body) 1703 1704def main(): 1705 wsi = { 1706 "Win32", 1707 "Android", 1708 "Xcb", 1709 "Xlib", 1710 "Wayland", 1711 "Mir", 1712 } 1713 1714 subcommands = { 1715 "object_tracker" : ObjectTrackerSubcommand, 1716 "unique_objects" : UniqueObjectsSubcommand, 1717 } 1718 1719 if len(sys.argv) < 4 or sys.argv[1] not in wsi or sys.argv[2] not in subcommands or not os.path.exists(sys.argv[3]): 1720 print("Usage: %s <wsi> <subcommand> <input_header> [options]" % sys.argv[0]) 1721 print 1722 print("Available subcommands are: %s" % " ".join(subcommands)) 1723 exit(1) 1724 1725 hfp = vk_helper.HeaderFileParser(sys.argv[3]) 1726 hfp.parse() 1727 vk_helper.enum_val_dict = hfp.get_enum_val_dict() 1728 vk_helper.enum_type_dict = hfp.get_enum_type_dict() 1729 vk_helper.struct_dict = hfp.get_struct_dict() 1730 vk_helper.typedef_fwd_dict = hfp.get_typedef_fwd_dict() 1731 vk_helper.typedef_rev_dict = hfp.get_typedef_rev_dict() 1732 vk_helper.types_dict = hfp.get_types_dict() 1733 1734 subcmd = subcommands[sys.argv[2]](sys.argv[3:]) 1735 subcmd.run() 1736 1737if __name__ == "__main__": 1738 main() 1739