1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2015-2019 The Khronos Group Inc. 4# Copyright (c) 2015-2019 Valve Corporation 5# Copyright (c) 2015-2019 LunarG, Inc. 6# Copyright (c) 2015-2019 Google Inc. 7# 8# Licensed under the Apache License, Version 2.0 (the "License"); 9# you may not use this file except in compliance with the License. 10# You may obtain a copy of the License at 11# 12# http://www.apache.org/licenses/LICENSE-2.0 13# 14# Unless required by applicable law or agreed to in writing, software 15# distributed under the License is distributed on an "AS IS" BASIS, 16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17# See the License for the specific language governing permissions and 18# limitations under the License. 19# 20# Author: Tobin Ehlis <tobine@google.com> 21# Author: Mark Lobodzinski <mark@lunarg.com> 22 23import os,re,sys 24import xml.etree.ElementTree as etree 25from generator import * 26from collections import namedtuple 27from common_codegen import * 28 29# LayerChassisDispatchGeneratorOptions - subclass of GeneratorOptions. 30# 31# Adds options used by LayerChassisDispatchOutputGenerator objects during 32# layer chassis dispatch file generation. 33# 34# Additional members 35# prefixText - list of strings to prefix generated header with 36# (usually a copyright statement + calling convention macros). 37# protectFile - True if multiple inclusion protection should be 38# generated (based on the filename) around the entire header. 39# protectFeature - True if #ifndef..#endif protection should be 40# generated around a feature interface in the header file. 41# genFuncPointers - True if function pointer typedefs should be 42# generated 43# protectProto - If conditional protection should be generated 44# around prototype declarations, set to either '#ifdef' 45# to require opt-in (#ifdef protectProtoStr) or '#ifndef' 46# to require opt-out (#ifndef protectProtoStr). Otherwise 47# set to None. 48# protectProtoStr - #ifdef/#ifndef symbol to use around prototype 49# declarations, if protectProto is set 50# apicall - string to use for the function declaration prefix, 51# such as APICALL on Windows. 52# apientry - string to use for the calling convention macro, 53# in typedefs, such as APIENTRY. 54# apientryp - string to use for the calling convention macro 55# in function pointer typedefs, such as APIENTRYP. 56# indentFuncProto - True if prototype declarations should put each 57# parameter on a separate line 58# indentFuncPointer - True if typedefed function pointers should put each 59# parameter on a separate line 60# alignFuncParam - if nonzero and parameters are being put on a 61# separate line, align parameter names at the specified column 62class LayerChassisDispatchGeneratorOptions(GeneratorOptions): 63 def __init__(self, 64 conventions = None, 65 filename = None, 66 directory = '.', 67 apiname = None, 68 profile = None, 69 versions = '.*', 70 emitversions = '.*', 71 defaultExtensions = None, 72 addExtensions = None, 73 removeExtensions = None, 74 emitExtensions = None, 75 sortProcedure = regSortFeatures, 76 prefixText = "", 77 genFuncPointers = True, 78 protectFile = True, 79 protectFeature = True, 80 apicall = '', 81 apientry = '', 82 apientryp = '', 83 indentFuncProto = True, 84 indentFuncPointer = False, 85 alignFuncParam = 0, 86 expandEnumerants = True): 87 GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile, 88 versions, emitversions, defaultExtensions, 89 addExtensions, removeExtensions, emitExtensions, sortProcedure) 90 self.prefixText = prefixText 91 self.genFuncPointers = genFuncPointers 92 self.protectFile = protectFile 93 self.protectFeature = protectFeature 94 self.apicall = apicall 95 self.apientry = apientry 96 self.apientryp = apientryp 97 self.indentFuncProto = indentFuncProto 98 self.indentFuncPointer = indentFuncPointer 99 self.alignFuncParam = alignFuncParam 100 self.expandEnumerants = expandEnumerants 101 102 103# LayerChassisDispatchOutputGenerator - subclass of OutputGenerator. 104# Generates layer chassis non-dispatchable handle-wrapping code. 105# 106# ---- methods ---- 107# LayerChassisDispatchOutputGenerator(errFile, warnFile, diagFile) - args as for OutputGenerator. Defines additional internal state. 108# ---- methods overriding base class ---- 109# beginFile(genOpts) 110# endFile() 111# beginFeature(interface, emit) 112# endFeature() 113# genCmd(cmdinfo) 114# genStruct() 115# genType() 116class LayerChassisDispatchOutputGenerator(OutputGenerator): 117 """Generate layer chassis handle wrapping code based on XML element attributes""" 118 inline_copyright_message = """ 119// This file is ***GENERATED***. Do Not Edit. 120// See layer_chassis_dispatch_generator.py for modifications. 121 122/* Copyright (c) 2015-2019 The Khronos Group Inc. 123 * Copyright (c) 2015-2019 Valve Corporation 124 * Copyright (c) 2015-2019 LunarG, Inc. 125 * Copyright (c) 2015-2019 Google Inc. 126 * 127 * Licensed under the Apache License, Version 2.0 (the "License"); 128 * you may not use this file except in compliance with the License. 129 * You may obtain a copy of the License at 130 * 131 * http://www.apache.org/licenses/LICENSE-2.0 132 * 133 * Unless required by applicable law or agreed to in writing, software 134 * distributed under the License is distributed on an "AS IS" BASIS, 135 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136 * See the License for the specific language governing permissions and 137 * limitations under the License. 138 * 139 * Author: Mark Lobodzinski <mark@lunarg.com> 140 */""" 141 142 inline_custom_source_preamble = """ 143VkResult DispatchCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 144 const VkComputePipelineCreateInfo *pCreateInfos, 145 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { 146 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 147 if (!wrap_handles) return layer_data->device_dispatch_table.CreateComputePipelines(device, pipelineCache, createInfoCount, 148 pCreateInfos, pAllocator, pPipelines); 149 safe_VkComputePipelineCreateInfo *local_pCreateInfos = NULL; 150 if (pCreateInfos) { 151 local_pCreateInfos = new safe_VkComputePipelineCreateInfo[createInfoCount]; 152 for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) { 153 local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]); 154 if (pCreateInfos[idx0].basePipelineHandle) { 155 local_pCreateInfos[idx0].basePipelineHandle = layer_data->Unwrap(pCreateInfos[idx0].basePipelineHandle); 156 } 157 if (pCreateInfos[idx0].layout) { 158 local_pCreateInfos[idx0].layout = layer_data->Unwrap(pCreateInfos[idx0].layout); 159 } 160 if (pCreateInfos[idx0].stage.module) { 161 local_pCreateInfos[idx0].stage.module = layer_data->Unwrap(pCreateInfos[idx0].stage.module); 162 } 163 } 164 } 165 if (pipelineCache) { 166 pipelineCache = layer_data->Unwrap(pipelineCache); 167 } 168 169 VkResult result = layer_data->device_dispatch_table.CreateComputePipelines(device, pipelineCache, createInfoCount, 170 local_pCreateInfos->ptr(), pAllocator, pPipelines); 171 delete[] local_pCreateInfos; 172 { 173 for (uint32_t i = 0; i < createInfoCount; ++i) { 174 if (pPipelines[i] != VK_NULL_HANDLE) { 175 pPipelines[i] = layer_data->WrapNew(pPipelines[i]); 176 } 177 } 178 } 179 return result; 180} 181 182VkResult DispatchCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, 183 const VkGraphicsPipelineCreateInfo *pCreateInfos, 184 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { 185 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 186 if (!wrap_handles) return layer_data->device_dispatch_table.CreateGraphicsPipelines(device, pipelineCache, createInfoCount, 187 pCreateInfos, pAllocator, pPipelines); 188 safe_VkGraphicsPipelineCreateInfo *local_pCreateInfos = nullptr; 189 if (pCreateInfos) { 190 local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount]; 191 read_dispatch_lock_guard_t lock(dispatch_lock); 192 for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) { 193 bool uses_color_attachment = false; 194 bool uses_depthstencil_attachment = false; 195 { 196 const auto subpasses_uses_it = layer_data->renderpasses_states.find(layer_data->Unwrap(pCreateInfos[idx0].renderPass)); 197 if (subpasses_uses_it != layer_data->renderpasses_states.end()) { 198 const auto &subpasses_uses = subpasses_uses_it->second; 199 if (subpasses_uses.subpasses_using_color_attachment.count(pCreateInfos[idx0].subpass)) 200 uses_color_attachment = true; 201 if (subpasses_uses.subpasses_using_depthstencil_attachment.count(pCreateInfos[idx0].subpass)) 202 uses_depthstencil_attachment = true; 203 } 204 } 205 206 local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0], uses_color_attachment, uses_depthstencil_attachment); 207 208 if (pCreateInfos[idx0].basePipelineHandle) { 209 local_pCreateInfos[idx0].basePipelineHandle = layer_data->Unwrap(pCreateInfos[idx0].basePipelineHandle); 210 } 211 if (pCreateInfos[idx0].layout) { 212 local_pCreateInfos[idx0].layout = layer_data->Unwrap(pCreateInfos[idx0].layout); 213 } 214 if (pCreateInfos[idx0].pStages) { 215 for (uint32_t idx1 = 0; idx1 < pCreateInfos[idx0].stageCount; ++idx1) { 216 if (pCreateInfos[idx0].pStages[idx1].module) { 217 local_pCreateInfos[idx0].pStages[idx1].module = layer_data->Unwrap(pCreateInfos[idx0].pStages[idx1].module); 218 } 219 } 220 } 221 if (pCreateInfos[idx0].renderPass) { 222 local_pCreateInfos[idx0].renderPass = layer_data->Unwrap(pCreateInfos[idx0].renderPass); 223 } 224 } 225 } 226 if (pipelineCache) { 227 pipelineCache = layer_data->Unwrap(pipelineCache); 228 } 229 230 VkResult result = layer_data->device_dispatch_table.CreateGraphicsPipelines(device, pipelineCache, createInfoCount, 231 local_pCreateInfos->ptr(), pAllocator, pPipelines); 232 delete[] local_pCreateInfos; 233 { 234 for (uint32_t i = 0; i < createInfoCount; ++i) { 235 if (pPipelines[i] != VK_NULL_HANDLE) { 236 pPipelines[i] = layer_data->WrapNew(pPipelines[i]); 237 } 238 } 239 } 240 return result; 241} 242 243template <typename T> 244static void UpdateCreateRenderPassState(ValidationObject *layer_data, const T *pCreateInfo, VkRenderPass renderPass) { 245 auto &renderpass_state = layer_data->renderpasses_states[renderPass]; 246 247 for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) { 248 bool uses_color = false; 249 for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i) 250 if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true; 251 252 bool uses_depthstencil = false; 253 if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment) 254 if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) 255 uses_depthstencil = true; 256 257 if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass); 258 if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass); 259 } 260} 261 262VkResult DispatchCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, 263 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { 264 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 265 VkResult result = layer_data->device_dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass); 266 if (!wrap_handles) return result; 267 if (VK_SUCCESS == result) { 268 write_dispatch_lock_guard_t lock(dispatch_lock); 269 UpdateCreateRenderPassState(layer_data, pCreateInfo, *pRenderPass); 270 *pRenderPass = layer_data->WrapNew(*pRenderPass); 271 } 272 return result; 273} 274 275VkResult DispatchCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2KHR *pCreateInfo, 276 const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { 277 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 278 VkResult result = layer_data->device_dispatch_table.CreateRenderPass2KHR(device, pCreateInfo, pAllocator, pRenderPass); 279 if (!wrap_handles) return result; 280 if (VK_SUCCESS == result) { 281 write_dispatch_lock_guard_t lock(dispatch_lock); 282 UpdateCreateRenderPassState(layer_data, pCreateInfo, *pRenderPass); 283 *pRenderPass = layer_data->WrapNew(*pRenderPass); 284 } 285 return result; 286} 287 288void DispatchDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) { 289 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 290 if (!wrap_handles) return layer_data->device_dispatch_table.DestroyRenderPass(device, renderPass, pAllocator); 291 uint64_t renderPass_id = reinterpret_cast<uint64_t &>(renderPass); 292 293 auto iter = unique_id_mapping.pop(renderPass_id); 294 if (iter != unique_id_mapping.end()) { 295 renderPass = (VkRenderPass)iter->second; 296 } else { 297 renderPass = (VkRenderPass)0; 298 } 299 300 layer_data->device_dispatch_table.DestroyRenderPass(device, renderPass, pAllocator); 301 302 write_dispatch_lock_guard_t lock(dispatch_lock); 303 layer_data->renderpasses_states.erase(renderPass); 304} 305 306VkResult DispatchCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, 307 const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) { 308 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 309 if (!wrap_handles) return layer_data->device_dispatch_table.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); 310 safe_VkSwapchainCreateInfoKHR *local_pCreateInfo = NULL; 311 if (pCreateInfo) { 312 local_pCreateInfo = new safe_VkSwapchainCreateInfoKHR(pCreateInfo); 313 local_pCreateInfo->oldSwapchain = layer_data->Unwrap(pCreateInfo->oldSwapchain); 314 // Surface is instance-level object 315 local_pCreateInfo->surface = layer_data->Unwrap(pCreateInfo->surface); 316 } 317 318 VkResult result = layer_data->device_dispatch_table.CreateSwapchainKHR(device, local_pCreateInfo->ptr(), pAllocator, pSwapchain); 319 delete local_pCreateInfo; 320 321 if (VK_SUCCESS == result) { 322 *pSwapchain = layer_data->WrapNew(*pSwapchain); 323 } 324 return result; 325} 326 327VkResult DispatchCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR *pCreateInfos, 328 const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains) { 329 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 330 if (!wrap_handles) 331 return layer_data->device_dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, pCreateInfos, pAllocator, 332 pSwapchains); 333 safe_VkSwapchainCreateInfoKHR *local_pCreateInfos = NULL; 334 { 335 if (pCreateInfos) { 336 local_pCreateInfos = new safe_VkSwapchainCreateInfoKHR[swapchainCount]; 337 for (uint32_t i = 0; i < swapchainCount; ++i) { 338 local_pCreateInfos[i].initialize(&pCreateInfos[i]); 339 if (pCreateInfos[i].surface) { 340 // Surface is instance-level object 341 local_pCreateInfos[i].surface = layer_data->Unwrap(pCreateInfos[i].surface); 342 } 343 if (pCreateInfos[i].oldSwapchain) { 344 local_pCreateInfos[i].oldSwapchain = layer_data->Unwrap(pCreateInfos[i].oldSwapchain); 345 } 346 } 347 } 348 } 349 VkResult result = layer_data->device_dispatch_table.CreateSharedSwapchainsKHR(device, swapchainCount, local_pCreateInfos->ptr(), 350 pAllocator, pSwapchains); 351 delete[] local_pCreateInfos; 352 if (VK_SUCCESS == result) { 353 for (uint32_t i = 0; i < swapchainCount; i++) { 354 pSwapchains[i] = layer_data->WrapNew(pSwapchains[i]); 355 } 356 } 357 return result; 358} 359 360VkResult DispatchGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, 361 VkImage *pSwapchainImages) { 362 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 363 if (!wrap_handles) 364 return layer_data->device_dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); 365 VkSwapchainKHR wrapped_swapchain_handle = swapchain; 366 if (VK_NULL_HANDLE != swapchain) { 367 swapchain = layer_data->Unwrap(swapchain); 368 } 369 VkResult result = 370 layer_data->device_dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); 371 if ((VK_SUCCESS == result) || (VK_INCOMPLETE == result)) { 372 if ((*pSwapchainImageCount > 0) && pSwapchainImages) { 373 write_dispatch_lock_guard_t lock(dispatch_lock); 374 auto &wrapped_swapchain_image_handles = layer_data->swapchain_wrapped_image_handle_map[wrapped_swapchain_handle]; 375 for (uint32_t i = static_cast<uint32_t>(wrapped_swapchain_image_handles.size()); i < *pSwapchainImageCount; i++) { 376 wrapped_swapchain_image_handles.emplace_back(layer_data->WrapNew(pSwapchainImages[i])); 377 } 378 for (uint32_t i = 0; i < *pSwapchainImageCount; i++) { 379 pSwapchainImages[i] = wrapped_swapchain_image_handles[i]; 380 } 381 } 382 } 383 return result; 384} 385 386void DispatchDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) { 387 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 388 if (!wrap_handles) return layer_data->device_dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator); 389 write_dispatch_lock_guard_t lock(dispatch_lock); 390 391 auto &image_array = layer_data->swapchain_wrapped_image_handle_map[swapchain]; 392 for (auto &image_handle : image_array) { 393 unique_id_mapping.erase(HandleToUint64(image_handle)); 394 } 395 layer_data->swapchain_wrapped_image_handle_map.erase(swapchain); 396 lock.unlock(); 397 398 uint64_t swapchain_id = HandleToUint64(swapchain); 399 400 auto iter = unique_id_mapping.pop(swapchain_id); 401 if (iter != unique_id_mapping.end()) { 402 swapchain = (VkSwapchainKHR)iter->second; 403 } else { 404 swapchain = (VkSwapchainKHR)0; 405 } 406 407 layer_data->device_dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator); 408} 409 410VkResult DispatchQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { 411 auto layer_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map); 412 if (!wrap_handles) return layer_data->device_dispatch_table.QueuePresentKHR(queue, pPresentInfo); 413 safe_VkPresentInfoKHR *local_pPresentInfo = NULL; 414 { 415 if (pPresentInfo) { 416 local_pPresentInfo = new safe_VkPresentInfoKHR(pPresentInfo); 417 if (local_pPresentInfo->pWaitSemaphores) { 418 for (uint32_t index1 = 0; index1 < local_pPresentInfo->waitSemaphoreCount; ++index1) { 419 local_pPresentInfo->pWaitSemaphores[index1] = layer_data->Unwrap(pPresentInfo->pWaitSemaphores[index1]); 420 } 421 } 422 if (local_pPresentInfo->pSwapchains) { 423 for (uint32_t index1 = 0; index1 < local_pPresentInfo->swapchainCount; ++index1) { 424 local_pPresentInfo->pSwapchains[index1] = layer_data->Unwrap(pPresentInfo->pSwapchains[index1]); 425 } 426 } 427 } 428 } 429 VkResult result = layer_data->device_dispatch_table.QueuePresentKHR(queue, local_pPresentInfo->ptr()); 430 431 // pResults is an output array embedded in a structure. The code generator neglects to copy back from the safe_* version, 432 // so handle it as a special case here: 433 if (pPresentInfo && pPresentInfo->pResults) { 434 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { 435 pPresentInfo->pResults[i] = local_pPresentInfo->pResults[i]; 436 } 437 } 438 delete local_pPresentInfo; 439 return result; 440} 441 442void DispatchDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) { 443 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 444 if (!wrap_handles) return layer_data->device_dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator); 445 write_dispatch_lock_guard_t lock(dispatch_lock); 446 447 // remove references to implicitly freed descriptor sets 448 for(auto descriptor_set : layer_data->pool_descriptor_sets_map[descriptorPool]) { 449 unique_id_mapping.erase(reinterpret_cast<uint64_t &>(descriptor_set)); 450 } 451 layer_data->pool_descriptor_sets_map.erase(descriptorPool); 452 lock.unlock(); 453 454 uint64_t descriptorPool_id = reinterpret_cast<uint64_t &>(descriptorPool); 455 456 auto iter = unique_id_mapping.pop(descriptorPool_id); 457 if (iter != unique_id_mapping.end()) { 458 descriptorPool = (VkDescriptorPool)iter->second; 459 } else { 460 descriptorPool = (VkDescriptorPool)0; 461 } 462 463 layer_data->device_dispatch_table.DestroyDescriptorPool(device, descriptorPool, pAllocator); 464} 465 466VkResult DispatchResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { 467 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 468 if (!wrap_handles) return layer_data->device_dispatch_table.ResetDescriptorPool(device, descriptorPool, flags); 469 VkDescriptorPool local_descriptor_pool = VK_NULL_HANDLE; 470 { 471 local_descriptor_pool = layer_data->Unwrap(descriptorPool); 472 } 473 VkResult result = layer_data->device_dispatch_table.ResetDescriptorPool(device, local_descriptor_pool, flags); 474 if (VK_SUCCESS == result) { 475 write_dispatch_lock_guard_t lock(dispatch_lock); 476 // remove references to implicitly freed descriptor sets 477 for(auto descriptor_set : layer_data->pool_descriptor_sets_map[descriptorPool]) { 478 unique_id_mapping.erase(reinterpret_cast<uint64_t &>(descriptor_set)); 479 } 480 layer_data->pool_descriptor_sets_map[descriptorPool].clear(); 481 } 482 483 return result; 484} 485 486VkResult DispatchAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, 487 VkDescriptorSet *pDescriptorSets) { 488 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 489 if (!wrap_handles) return layer_data->device_dispatch_table.AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets); 490 safe_VkDescriptorSetAllocateInfo *local_pAllocateInfo = NULL; 491 { 492 if (pAllocateInfo) { 493 local_pAllocateInfo = new safe_VkDescriptorSetAllocateInfo(pAllocateInfo); 494 if (pAllocateInfo->descriptorPool) { 495 local_pAllocateInfo->descriptorPool = layer_data->Unwrap(pAllocateInfo->descriptorPool); 496 } 497 if (local_pAllocateInfo->pSetLayouts) { 498 for (uint32_t index1 = 0; index1 < local_pAllocateInfo->descriptorSetCount; ++index1) { 499 local_pAllocateInfo->pSetLayouts[index1] = layer_data->Unwrap(local_pAllocateInfo->pSetLayouts[index1]); 500 } 501 } 502 } 503 } 504 VkResult result = layer_data->device_dispatch_table.AllocateDescriptorSets( 505 device, (const VkDescriptorSetAllocateInfo *)local_pAllocateInfo, pDescriptorSets); 506 if (local_pAllocateInfo) { 507 delete local_pAllocateInfo; 508 } 509 if (VK_SUCCESS == result) { 510 write_dispatch_lock_guard_t lock(dispatch_lock); 511 auto &pool_descriptor_sets = layer_data->pool_descriptor_sets_map[pAllocateInfo->descriptorPool]; 512 for (uint32_t index0 = 0; index0 < pAllocateInfo->descriptorSetCount; index0++) { 513 pDescriptorSets[index0] = layer_data->WrapNew(pDescriptorSets[index0]); 514 pool_descriptor_sets.insert(pDescriptorSets[index0]); 515 } 516 } 517 return result; 518} 519 520VkResult DispatchFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, 521 const VkDescriptorSet *pDescriptorSets) { 522 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 523 if (!wrap_handles) 524 return layer_data->device_dispatch_table.FreeDescriptorSets(device, descriptorPool, descriptorSetCount, pDescriptorSets); 525 VkDescriptorSet *local_pDescriptorSets = NULL; 526 VkDescriptorPool local_descriptor_pool = VK_NULL_HANDLE; 527 { 528 local_descriptor_pool = layer_data->Unwrap(descriptorPool); 529 if (pDescriptorSets) { 530 local_pDescriptorSets = new VkDescriptorSet[descriptorSetCount]; 531 for (uint32_t index0 = 0; index0 < descriptorSetCount; ++index0) { 532 local_pDescriptorSets[index0] = layer_data->Unwrap(pDescriptorSets[index0]); 533 } 534 } 535 } 536 VkResult result = layer_data->device_dispatch_table.FreeDescriptorSets(device, local_descriptor_pool, descriptorSetCount, 537 (const VkDescriptorSet *)local_pDescriptorSets); 538 if (local_pDescriptorSets) delete[] local_pDescriptorSets; 539 if ((VK_SUCCESS == result) && (pDescriptorSets)) { 540 write_dispatch_lock_guard_t lock(dispatch_lock); 541 auto &pool_descriptor_sets = layer_data->pool_descriptor_sets_map[descriptorPool]; 542 for (uint32_t index0 = 0; index0 < descriptorSetCount; index0++) { 543 VkDescriptorSet handle = pDescriptorSets[index0]; 544 pool_descriptor_sets.erase(handle); 545 uint64_t unique_id = reinterpret_cast<uint64_t &>(handle); 546 unique_id_mapping.erase(unique_id); 547 } 548 } 549 return result; 550} 551 552// This is the core version of this routine. The extension version is below. 553VkResult DispatchCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, 554 const VkAllocationCallbacks *pAllocator, 555 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) { 556 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 557 if (!wrap_handles) 558 return layer_data->device_dispatch_table.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, 559 pDescriptorUpdateTemplate); 560 safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = NULL; 561 { 562 if (pCreateInfo) { 563 local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo); 564 if (pCreateInfo->descriptorSetLayout) { 565 local_create_info->descriptorSetLayout = layer_data->Unwrap(pCreateInfo->descriptorSetLayout); 566 } 567 if (pCreateInfo->pipelineLayout) { 568 local_create_info->pipelineLayout = layer_data->Unwrap(pCreateInfo->pipelineLayout); 569 } 570 } 571 } 572 VkResult result = layer_data->device_dispatch_table.CreateDescriptorUpdateTemplate(device, local_create_info->ptr(), pAllocator, 573 pDescriptorUpdateTemplate); 574 if (VK_SUCCESS == result) { 575 write_dispatch_lock_guard_t lock(dispatch_lock); 576 *pDescriptorUpdateTemplate = layer_data->WrapNew(*pDescriptorUpdateTemplate); 577 578 // Shadow template createInfo for later updates 579 std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info)); 580 layer_data->desc_template_createinfo_map[(uint64_t)*pDescriptorUpdateTemplate] = std::move(template_state); 581 } 582 return result; 583} 584 585// This is the extension version of this routine. The core version is above. 586VkResult DispatchCreateDescriptorUpdateTemplateKHR(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, 587 const VkAllocationCallbacks *pAllocator, 588 VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) { 589 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 590 if (!wrap_handles) 591 return layer_data->device_dispatch_table.CreateDescriptorUpdateTemplateKHR(device, pCreateInfo, pAllocator, 592 pDescriptorUpdateTemplate); 593 safe_VkDescriptorUpdateTemplateCreateInfo *local_create_info = NULL; 594 { 595 if (pCreateInfo) { 596 local_create_info = new safe_VkDescriptorUpdateTemplateCreateInfo(pCreateInfo); 597 if (pCreateInfo->descriptorSetLayout) { 598 local_create_info->descriptorSetLayout = layer_data->Unwrap(pCreateInfo->descriptorSetLayout); 599 } 600 if (pCreateInfo->pipelineLayout) { 601 local_create_info->pipelineLayout = layer_data->Unwrap(pCreateInfo->pipelineLayout); 602 } 603 } 604 } 605 VkResult result = layer_data->device_dispatch_table.CreateDescriptorUpdateTemplateKHR(device, local_create_info->ptr(), pAllocator, 606 pDescriptorUpdateTemplate); 607 if (VK_SUCCESS == result) { 608 write_dispatch_lock_guard_t lock(dispatch_lock); 609 *pDescriptorUpdateTemplate = layer_data->WrapNew(*pDescriptorUpdateTemplate); 610 611 // Shadow template createInfo for later updates 612 std::unique_ptr<TEMPLATE_STATE> template_state(new TEMPLATE_STATE(*pDescriptorUpdateTemplate, local_create_info)); 613 layer_data->desc_template_createinfo_map[(uint64_t)*pDescriptorUpdateTemplate] = std::move(template_state); 614 } 615 return result; 616} 617 618// This is the core version of this routine. The extension version is below. 619void DispatchDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, 620 const VkAllocationCallbacks *pAllocator) { 621 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 622 if (!wrap_handles) 623 return layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); 624 write_dispatch_lock_guard_t lock(dispatch_lock); 625 uint64_t descriptor_update_template_id = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate); 626 layer_data->desc_template_createinfo_map.erase(descriptor_update_template_id); 627 lock.unlock(); 628 629 auto iter = unique_id_mapping.pop(descriptor_update_template_id); 630 if (iter != unique_id_mapping.end()) { 631 descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)iter->second; 632 } else { 633 descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)0; 634 } 635 636 layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); 637} 638 639// This is the extension version of this routine. The core version is above. 640void DispatchDestroyDescriptorUpdateTemplateKHR(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, 641 const VkAllocationCallbacks *pAllocator) { 642 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 643 if (!wrap_handles) 644 return layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator); 645 write_dispatch_lock_guard_t lock(dispatch_lock); 646 uint64_t descriptor_update_template_id = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate); 647 layer_data->desc_template_createinfo_map.erase(descriptor_update_template_id); 648 lock.unlock(); 649 650 auto iter = unique_id_mapping.pop(descriptor_update_template_id); 651 if (iter != unique_id_mapping.end()) { 652 descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)iter->second; 653 } else { 654 descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)0; 655 } 656 657 layer_data->device_dispatch_table.DestroyDescriptorUpdateTemplateKHR(device, descriptorUpdateTemplate, pAllocator); 658} 659 660void *BuildUnwrappedUpdateTemplateBuffer(ValidationObject *layer_data, uint64_t descriptorUpdateTemplate, const void *pData) { 661 auto const template_map_entry = layer_data->desc_template_createinfo_map.find(descriptorUpdateTemplate); 662 if (template_map_entry == layer_data->desc_template_createinfo_map.end()) { 663 assert(0); 664 } 665 auto const &create_info = template_map_entry->second->create_info; 666 size_t allocation_size = 0; 667 std::vector<std::tuple<size_t, VulkanObjectType, uint64_t, size_t>> template_entries; 668 669 for (uint32_t i = 0; i < create_info.descriptorUpdateEntryCount; i++) { 670 for (uint32_t j = 0; j < create_info.pDescriptorUpdateEntries[i].descriptorCount; j++) { 671 size_t offset = create_info.pDescriptorUpdateEntries[i].offset + j * create_info.pDescriptorUpdateEntries[i].stride; 672 char *update_entry = (char *)(pData) + offset; 673 674 switch (create_info.pDescriptorUpdateEntries[i].descriptorType) { 675 case VK_DESCRIPTOR_TYPE_SAMPLER: 676 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 677 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 678 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: 679 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { 680 auto image_entry = reinterpret_cast<VkDescriptorImageInfo *>(update_entry); 681 allocation_size = std::max(allocation_size, offset + sizeof(VkDescriptorImageInfo)); 682 683 VkDescriptorImageInfo *wrapped_entry = new VkDescriptorImageInfo(*image_entry); 684 wrapped_entry->sampler = layer_data->Unwrap(image_entry->sampler); 685 wrapped_entry->imageView = layer_data->Unwrap(image_entry->imageView); 686 template_entries.emplace_back(offset, kVulkanObjectTypeImage, CastToUint64(wrapped_entry), 0); 687 } break; 688 689 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 690 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 691 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 692 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { 693 auto buffer_entry = reinterpret_cast<VkDescriptorBufferInfo *>(update_entry); 694 allocation_size = std::max(allocation_size, offset + sizeof(VkDescriptorBufferInfo)); 695 696 VkDescriptorBufferInfo *wrapped_entry = new VkDescriptorBufferInfo(*buffer_entry); 697 wrapped_entry->buffer = layer_data->Unwrap(buffer_entry->buffer); 698 template_entries.emplace_back(offset, kVulkanObjectTypeBuffer, CastToUint64(wrapped_entry), 0); 699 } break; 700 701 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: 702 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { 703 auto buffer_view_handle = reinterpret_cast<VkBufferView *>(update_entry); 704 allocation_size = std::max(allocation_size, offset + sizeof(VkBufferView)); 705 706 VkBufferView wrapped_entry = layer_data->Unwrap(*buffer_view_handle); 707 template_entries.emplace_back(offset, kVulkanObjectTypeBufferView, CastToUint64(wrapped_entry), 0); 708 } break; 709 case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: { 710 size_t numBytes = create_info.pDescriptorUpdateEntries[i].descriptorCount; 711 allocation_size = std::max(allocation_size, offset + numBytes); 712 // nothing to unwrap, just plain data 713 template_entries.emplace_back(offset, kVulkanObjectTypeUnknown, CastToUint64(update_entry), 714 numBytes); 715 // to break out of the loop 716 j = create_info.pDescriptorUpdateEntries[i].descriptorCount; 717 } break; 718 default: 719 assert(0); 720 break; 721 } 722 } 723 } 724 // Allocate required buffer size and populate with source/unwrapped data 725 void *unwrapped_data = malloc(allocation_size); 726 for (auto &this_entry : template_entries) { 727 VulkanObjectType type = std::get<1>(this_entry); 728 void *destination = (char *)unwrapped_data + std::get<0>(this_entry); 729 uint64_t source = std::get<2>(this_entry); 730 size_t size = std::get<3>(this_entry); 731 732 if (size != 0) { 733 assert(type == kVulkanObjectTypeUnknown); 734 memcpy(destination, CastFromUint64<void *>(source), size); 735 } else { 736 switch (type) { 737 case kVulkanObjectTypeImage: 738 *(reinterpret_cast<VkDescriptorImageInfo *>(destination)) = 739 *(reinterpret_cast<VkDescriptorImageInfo *>(source)); 740 delete CastFromUint64<VkDescriptorImageInfo *>(source); 741 break; 742 case kVulkanObjectTypeBuffer: 743 *(reinterpret_cast<VkDescriptorBufferInfo *>(destination)) = 744 *(CastFromUint64<VkDescriptorBufferInfo *>(source)); 745 delete CastFromUint64<VkDescriptorBufferInfo *>(source); 746 break; 747 case kVulkanObjectTypeBufferView: 748 *(reinterpret_cast<VkBufferView *>(destination)) = CastFromUint64<VkBufferView>(source); 749 break; 750 default: 751 assert(0); 752 break; 753 } 754 } 755 } 756 return (void *)unwrapped_data; 757} 758 759void DispatchUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, 760 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void *pData) { 761 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 762 if (!wrap_handles) 763 return layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, 764 pData); 765 uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate); 766 void *unwrapped_buffer = nullptr; 767 { 768 read_dispatch_lock_guard_t lock(dispatch_lock); 769 descriptorSet = layer_data->Unwrap(descriptorSet); 770 descriptorUpdateTemplate = (VkDescriptorUpdateTemplate)layer_data->Unwrap(descriptorUpdateTemplate); 771 unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(layer_data, template_handle, pData); 772 } 773 layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, unwrapped_buffer); 774 free(unwrapped_buffer); 775} 776 777void DispatchUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet, 778 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void *pData) { 779 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 780 if (!wrap_handles) 781 return layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, 782 pData); 783 uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate); 784 void *unwrapped_buffer = nullptr; 785 { 786 read_dispatch_lock_guard_t lock(dispatch_lock); 787 descriptorSet = layer_data->Unwrap(descriptorSet); 788 descriptorUpdateTemplate = layer_data->Unwrap(descriptorUpdateTemplate); 789 unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(layer_data, template_handle, pData); 790 } 791 layer_data->device_dispatch_table.UpdateDescriptorSetWithTemplateKHR(device, descriptorSet, descriptorUpdateTemplate, unwrapped_buffer); 792 free(unwrapped_buffer); 793} 794 795void DispatchCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer, 796 VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, 797 uint32_t set, const void *pData) { 798 auto layer_data = GetLayerDataPtr(get_dispatch_key(commandBuffer), layer_data_map); 799 if (!wrap_handles) 800 return layer_data->device_dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, 801 layout, set, pData); 802 uint64_t template_handle = reinterpret_cast<uint64_t &>(descriptorUpdateTemplate); 803 void *unwrapped_buffer = nullptr; 804 { 805 read_dispatch_lock_guard_t lock(dispatch_lock); 806 descriptorUpdateTemplate = layer_data->Unwrap(descriptorUpdateTemplate); 807 layout = layer_data->Unwrap(layout); 808 unwrapped_buffer = BuildUnwrappedUpdateTemplateBuffer(layer_data, template_handle, pData); 809 } 810 layer_data->device_dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, 811 unwrapped_buffer); 812 free(unwrapped_buffer); 813} 814 815VkResult DispatchGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, 816 VkDisplayPropertiesKHR *pProperties) { 817 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 818 VkResult result = 819 layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, pPropertyCount, pProperties); 820 if (!wrap_handles) return result; 821 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) { 822 for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) { 823 pProperties[idx0].display = layer_data->MaybeWrapDisplay(pProperties[idx0].display, layer_data); 824 } 825 } 826 return result; 827} 828 829VkResult DispatchGetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, 830 VkDisplayProperties2KHR *pProperties) { 831 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 832 VkResult result = 833 layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, pPropertyCount, pProperties); 834 if (!wrap_handles) return result; 835 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) { 836 for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) { 837 pProperties[idx0].displayProperties.display = 838 layer_data->MaybeWrapDisplay(pProperties[idx0].displayProperties.display, layer_data); 839 } 840 } 841 return result; 842} 843 844VkResult DispatchGetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, 845 VkDisplayPlanePropertiesKHR *pProperties) { 846 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 847 VkResult result = 848 layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, pPropertyCount, pProperties); 849 if (!wrap_handles) return result; 850 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) { 851 for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) { 852 VkDisplayKHR &opt_display = pProperties[idx0].currentDisplay; 853 if (opt_display) opt_display = layer_data->MaybeWrapDisplay(opt_display, layer_data); 854 } 855 } 856 return result; 857} 858 859VkResult DispatchGetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, 860 VkDisplayPlaneProperties2KHR *pProperties) { 861 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 862 VkResult result = layer_data->instance_dispatch_table.GetPhysicalDeviceDisplayPlaneProperties2KHR(physicalDevice, 863 pPropertyCount, pProperties); 864 if (!wrap_handles) return result; 865 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) { 866 for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) { 867 VkDisplayKHR &opt_display = pProperties[idx0].displayPlaneProperties.currentDisplay; 868 if (opt_display) opt_display = layer_data->MaybeWrapDisplay(opt_display, layer_data); 869 } 870 } 871 return result; 872} 873 874VkResult DispatchGetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t *pDisplayCount, 875 VkDisplayKHR *pDisplays) { 876 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 877 VkResult result = layer_data->instance_dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, 878 pDisplayCount, pDisplays); 879 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pDisplays) { 880 if (!wrap_handles) return result; 881 for (uint32_t i = 0; i < *pDisplayCount; ++i) { 882 if (pDisplays[i]) pDisplays[i] = layer_data->MaybeWrapDisplay(pDisplays[i], layer_data); 883 } 884 } 885 return result; 886} 887 888VkResult DispatchGetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, 889 VkDisplayModePropertiesKHR *pProperties) { 890 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 891 if (!wrap_handles) 892 return layer_data->instance_dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, 893 pProperties); 894 { 895 display = layer_data->Unwrap(display); 896 } 897 898 VkResult result = layer_data->instance_dispatch_table.GetDisplayModePropertiesKHR(physicalDevice, display, pPropertyCount, pProperties); 899 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) { 900 for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) { 901 pProperties[idx0].displayMode = layer_data->WrapNew(pProperties[idx0].displayMode); 902 } 903 } 904 return result; 905} 906 907VkResult DispatchGetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t *pPropertyCount, 908 VkDisplayModeProperties2KHR *pProperties) { 909 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map); 910 if (!wrap_handles) 911 return layer_data->instance_dispatch_table.GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, 912 pProperties); 913 { 914 display = layer_data->Unwrap(display); 915 } 916 917 VkResult result = 918 layer_data->instance_dispatch_table.GetDisplayModeProperties2KHR(physicalDevice, display, pPropertyCount, pProperties); 919 if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pProperties) { 920 for (uint32_t idx0 = 0; idx0 < *pPropertyCount; ++idx0) { 921 pProperties[idx0].displayModeProperties.displayMode = layer_data->WrapNew(pProperties[idx0].displayModeProperties.displayMode); 922 } 923 } 924 return result; 925} 926 927VkResult DispatchDebugMarkerSetObjectTagEXT(VkDevice device, const VkDebugMarkerObjectTagInfoEXT *pTagInfo) { 928 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 929 if (!wrap_handles) return layer_data->device_dispatch_table.DebugMarkerSetObjectTagEXT(device, pTagInfo); 930 safe_VkDebugMarkerObjectTagInfoEXT local_tag_info(pTagInfo); 931 { 932 auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info.object)); 933 if (it != unique_id_mapping.end()) { 934 local_tag_info.object = it->second; 935 } 936 } 937 VkResult result = layer_data->device_dispatch_table.DebugMarkerSetObjectTagEXT(device, 938 reinterpret_cast<VkDebugMarkerObjectTagInfoEXT *>(&local_tag_info)); 939 return result; 940} 941 942VkResult DispatchDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) { 943 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 944 if (!wrap_handles) return layer_data->device_dispatch_table.DebugMarkerSetObjectNameEXT(device, pNameInfo); 945 safe_VkDebugMarkerObjectNameInfoEXT local_name_info(pNameInfo); 946 { 947 auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info.object)); 948 if (it != unique_id_mapping.end()) { 949 local_name_info.object = it->second; 950 } 951 } 952 VkResult result = layer_data->device_dispatch_table.DebugMarkerSetObjectNameEXT( 953 device, reinterpret_cast<VkDebugMarkerObjectNameInfoEXT *>(&local_name_info)); 954 return result; 955} 956 957// VK_EXT_debug_utils 958VkResult DispatchSetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) { 959 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 960 if (!wrap_handles) return layer_data->device_dispatch_table.SetDebugUtilsObjectTagEXT(device, pTagInfo); 961 safe_VkDebugUtilsObjectTagInfoEXT local_tag_info(pTagInfo); 962 { 963 auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_tag_info.objectHandle)); 964 if (it != unique_id_mapping.end()) { 965 local_tag_info.objectHandle = it->second; 966 } 967 } 968 VkResult result = layer_data->device_dispatch_table.SetDebugUtilsObjectTagEXT( 969 device, reinterpret_cast<const VkDebugUtilsObjectTagInfoEXT *>(&local_tag_info)); 970 return result; 971} 972 973VkResult DispatchSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) { 974 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map); 975 if (!wrap_handles) return layer_data->device_dispatch_table.SetDebugUtilsObjectNameEXT(device, pNameInfo); 976 safe_VkDebugUtilsObjectNameInfoEXT local_name_info(pNameInfo); 977 { 978 auto it = unique_id_mapping.find(reinterpret_cast<uint64_t &>(local_name_info.objectHandle)); 979 if (it != unique_id_mapping.end()) { 980 local_name_info.objectHandle = it->second; 981 } 982 } 983 VkResult result = layer_data->device_dispatch_table.SetDebugUtilsObjectNameEXT( 984 device, reinterpret_cast<const VkDebugUtilsObjectNameInfoEXT *>(&local_name_info)); 985 return result; 986} 987 988""" 989 # Separate generated text for source and headers 990 ALL_SECTIONS = ['source_file', 'header_file'] 991 def __init__(self, 992 errFile = sys.stderr, 993 warnFile = sys.stderr, 994 diagFile = sys.stdout): 995 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 996 self.INDENT_SPACES = 4 997 self.instance_extensions = [] 998 self.device_extensions = [] 999 # Commands which are not autogenerated but still intercepted 1000 self.no_autogen_list = [ 1001 'vkCreateInstance', 1002 'vkDestroyInstance', 1003 'vkCreateDevice', 1004 'vkDestroyDevice', 1005 'vkCreateComputePipelines', 1006 'vkCreateGraphicsPipelines', 1007 'vkCreateSwapchainKHR', 1008 'vkCreateSharedSwapchainsKHR', 1009 'vkGetSwapchainImagesKHR', 1010 'vkDestroySwapchainKHR', 1011 'vkQueuePresentKHR', 1012 'vkResetDescriptorPool', 1013 'vkDestroyDescriptorPool', 1014 'vkAllocateDescriptorSets', 1015 'vkFreeDescriptorSets', 1016 'vkCreateDescriptorUpdateTemplate', 1017 'vkCreateDescriptorUpdateTemplateKHR', 1018 'vkDestroyDescriptorUpdateTemplate', 1019 'vkDestroyDescriptorUpdateTemplateKHR', 1020 'vkUpdateDescriptorSetWithTemplate', 1021 'vkUpdateDescriptorSetWithTemplateKHR', 1022 'vkCmdPushDescriptorSetWithTemplateKHR', 1023 'vkDebugMarkerSetObjectTagEXT', 1024 'vkDebugMarkerSetObjectNameEXT', 1025 'vkCreateRenderPass', 1026 'vkCreateRenderPass2KHR', 1027 'vkDestroyRenderPass', 1028 'vkSetDebugUtilsObjectNameEXT', 1029 'vkSetDebugUtilsObjectTagEXT', 1030 'vkGetPhysicalDeviceDisplayPropertiesKHR', 1031 'vkGetPhysicalDeviceDisplayProperties2KHR', 1032 'vkGetPhysicalDeviceDisplayPlanePropertiesKHR', 1033 'vkGetPhysicalDeviceDisplayPlaneProperties2KHR', 1034 'vkGetDisplayPlaneSupportedDisplaysKHR', 1035 'vkGetDisplayModePropertiesKHR', 1036 'vkGetDisplayModeProperties2KHR', 1037 'vkEnumerateInstanceExtensionProperties', 1038 'vkEnumerateInstanceLayerProperties', 1039 'vkEnumerateDeviceExtensionProperties', 1040 'vkEnumerateDeviceLayerProperties', 1041 'vkEnumerateInstanceVersion', 1042 ] 1043 self.headerVersion = None 1044 # Internal state - accumulators for different inner block text 1045 self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) 1046 1047 self.cmdMembers = [] 1048 self.cmd_feature_protect = [] # Save ifdef's for each command 1049 self.cmd_info_data = [] # Save the cmdinfo data for wrapping the handles when processing is complete 1050 self.structMembers = [] # List of StructMemberData records for all Vulkan structs 1051 self.extension_structs = [] # List of all structs or sister-structs containing handles 1052 # A sister-struct may contain no handles but shares a structextends attribute with one that does 1053 self.pnext_extension_structs = [] # List of all structs which can be extended by a pnext chain 1054 self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType 1055 self.struct_member_dict = dict() 1056 # Named tuples to store struct and command data 1057 self.StructType = namedtuple('StructType', ['name', 'value']) 1058 self.CmdMemberData = namedtuple('CmdMemberData', ['name', 'members']) 1059 self.CmdInfoData = namedtuple('CmdInfoData', ['name', 'cmdinfo']) 1060 self.CmdExtraProtect = namedtuple('CmdExtraProtect', ['name', 'extra_protect']) 1061 1062 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl', 'islocal', 'iscreate', 'isdestroy', 'feature_protect']) 1063 self.StructMemberData = namedtuple('StructMemberData', ['name', 'members']) 1064 # 1065 def incIndent(self, indent): 1066 inc = ' ' * self.INDENT_SPACES 1067 if indent: 1068 return indent + inc 1069 return inc 1070 # 1071 def decIndent(self, indent): 1072 if indent and (len(indent) > self.INDENT_SPACES): 1073 return indent[:-self.INDENT_SPACES] 1074 return '' 1075 # 1076 # Override makeProtoName to drop the "vk" prefix 1077 def makeProtoName(self, name, tail): 1078 return self.genOpts.apientry + name[2:] + tail 1079 # 1080 # Check if the parameter passed in is a pointer to an array 1081 def paramIsArray(self, param): 1082 return param.attrib.get('len') is not None 1083 # 1084 def beginFile(self, genOpts): 1085 OutputGenerator.beginFile(self, genOpts) 1086 # Initialize members that require the tree 1087 self.handle_types = GetHandleTypes(self.registry.tree) 1088 self.type_categories = GetTypeCategories(self.registry.tree) 1089 # Output Copyright 1090 self.appendSection('header_file', self.inline_copyright_message) 1091 # Multiple inclusion protection & C++ namespace. 1092 self.header = False 1093 if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]): 1094 self.header = True 1095 self.appendSection('header_file', '#pragma once') 1096 self.appendSection('header_file', '') 1097 self.appendSection('header_file', '#if defined(LAYER_CHASSIS_CAN_WRAP_HANDLES)') 1098 self.appendSection('header_file', 'extern bool wrap_handles;') 1099 self.appendSection('header_file', '#else') 1100 self.appendSection('header_file', 'extern bool wrap_handles;') 1101 self.appendSection('header_file', '#endif') 1102 1103 # Now that the data is all collected and complete, generate and output the wrapping/unwrapping routines 1104 def endFile(self): 1105 self.struct_member_dict = dict(self.structMembers) 1106 # Generate the list of APIs that might need to handle wrapped extension structs 1107 self.GenerateCommandWrapExtensionList() 1108 # Write out wrapping/unwrapping functions 1109 self.WrapCommands() 1110 # Build and write out pNext processing function 1111 extension_proc = self.build_extension_processing_func() 1112 1113 if not self.header: 1114 write(self.inline_copyright_message, file=self.outFile) 1115 self.newline() 1116 write('#include <mutex>', file=self.outFile) 1117 write('#include "chassis.h"', file=self.outFile) 1118 write('#include "layer_chassis_dispatch.h"', file=self.outFile) 1119 write('#include "vk_layer_utils.h"', file=self.outFile) 1120 self.newline() 1121 write('// This intentionally includes a cpp file', file=self.outFile) 1122 write('#include "vk_safe_struct.cpp"', file=self.outFile) 1123 self.newline() 1124 write('// shared_mutex support added in MSVC 2015 update 2', file=self.outFile) 1125 write('#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && NTDDI_VERSION > NTDDI_WIN10_RS2', file=self.outFile) 1126 write(' #include <shared_mutex>', file=self.outFile) 1127 write(' typedef std::shared_mutex dispatch_lock_t;', file=self.outFile) 1128 write(' typedef std::shared_lock<dispatch_lock_t> read_dispatch_lock_guard_t;', file=self.outFile) 1129 write(' typedef std::unique_lock<dispatch_lock_t> write_dispatch_lock_guard_t;', file=self.outFile) 1130 write('#else', file=self.outFile) 1131 write(' typedef std::mutex dispatch_lock_t;', file=self.outFile) 1132 write(' typedef std::unique_lock<dispatch_lock_t> read_dispatch_lock_guard_t;', file=self.outFile) 1133 write(' typedef std::unique_lock<dispatch_lock_t> write_dispatch_lock_guard_t;', file=self.outFile) 1134 write('#endif', file=self.outFile) 1135 write('dispatch_lock_t dispatch_lock;', file=self.outFile) 1136 self.newline() 1137 write('// Unique Objects pNext extension handling function', file=self.outFile) 1138 write('%s' % extension_proc, file=self.outFile) 1139 self.newline() 1140 write('// Manually written Dispatch routines', file=self.outFile) 1141 write('%s' % self.inline_custom_source_preamble, file=self.outFile) 1142 self.newline() 1143 if (self.sections['source_file']): 1144 write('\n'.join(self.sections['source_file']), end=u'', file=self.outFile) 1145 else: 1146 self.newline() 1147 if (self.sections['header_file']): 1148 write('\n'.join(self.sections['header_file']), end=u'', file=self.outFile) 1149 1150 # Finish processing in superclass 1151 OutputGenerator.endFile(self) 1152 # 1153 def beginFeature(self, interface, emit): 1154 # Start processing in superclass 1155 OutputGenerator.beginFeature(self, interface, emit) 1156 self.headerVersion = None 1157 self.featureExtraProtect = GetFeatureProtect(interface) 1158 if self.featureName != 'VK_VERSION_1_0' and self.featureName != 'VK_VERSION_1_1': 1159 white_list_entry = [] 1160 if (self.featureExtraProtect is not None): 1161 white_list_entry += [ '#ifdef %s' % self.featureExtraProtect ] 1162 white_list_entry += [ '"%s"' % self.featureName ] 1163 if (self.featureExtraProtect is not None): 1164 white_list_entry += [ '#endif' ] 1165 featureType = interface.get('type') 1166 if featureType == 'instance': 1167 self.instance_extensions += white_list_entry 1168 elif featureType == 'device': 1169 self.device_extensions += white_list_entry 1170 # 1171 def endFeature(self): 1172 # Finish processing in superclass 1173 OutputGenerator.endFeature(self) 1174 # 1175 def genType(self, typeinfo, name, alias): 1176 OutputGenerator.genType(self, typeinfo, name, alias) 1177 typeElem = typeinfo.elem 1178 # If the type is a struct type, traverse the imbedded <member> tags generating a structure. 1179 # Otherwise, emit the tag text. 1180 category = typeElem.get('category') 1181 if (category == 'struct' or category == 'union'): 1182 self.genStruct(typeinfo, name, alias) 1183 # 1184 # Append a definition to the specified section 1185 def appendSection(self, section, text): 1186 # self.sections[section].append('SECTION: ' + section + '\n') 1187 self.sections[section].append(text) 1188 # 1189 # Check if the parameter passed in is a pointer 1190 def paramIsPointer(self, param): 1191 ispointer = False 1192 for elem in param: 1193 if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail: 1194 ispointer = True 1195 return ispointer 1196 # 1197 # Retrieve the type and name for a parameter 1198 def getTypeNameTuple(self, param): 1199 type = '' 1200 name = '' 1201 for elem in param: 1202 if elem.tag == 'type': 1203 type = noneStr(elem.text) 1204 elif elem.tag == 'name': 1205 name = noneStr(elem.text) 1206 return (type, name) 1207 # 1208 # Retrieve the value of the len tag 1209 def getLen(self, param): 1210 result = None 1211 len = param.attrib.get('len') 1212 if len and len != 'null-terminated': 1213 # For string arrays, 'len' can look like 'count,null-terminated', indicating that we 1214 # have a null terminated array of strings. We strip the null-terminated from the 1215 # 'len' field and only return the parameter specifying the string count 1216 if 'null-terminated' in len: 1217 result = len.split(',')[0] 1218 else: 1219 result = len 1220 # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol 1221 result = str(result).replace('::', '->') 1222 return result 1223 # 1224 # Generate a VkStructureType based on a structure typename 1225 def genVkStructureType(self, typename): 1226 # Add underscore between lowercase then uppercase 1227 value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename) 1228 # Change to uppercase 1229 value = value.upper() 1230 # Add STRUCTURE_TYPE_ 1231 return re.sub('VK_', 'VK_STRUCTURE_TYPE_', value) 1232 # 1233 # Struct parameter check generation. 1234 # This is a special case of the <type> tag where the contents are interpreted as a set of 1235 # <member> tags instead of freeform C type declarations. The <member> tags are just like 1236 # <param> tags - they are a declaration of a struct or union member. Only simple member 1237 # declarations are supported (no nested structs etc.) 1238 def genStruct(self, typeinfo, typeName, alias): 1239 OutputGenerator.genStruct(self, typeinfo, typeName, alias) 1240 members = typeinfo.elem.findall('.//member') 1241 # Iterate over members once to get length parameters for arrays 1242 lens = set() 1243 for member in members: 1244 len = self.getLen(member) 1245 if len: 1246 lens.add(len) 1247 # Generate member info 1248 membersInfo = [] 1249 for member in members: 1250 # Get the member's type and name 1251 info = self.getTypeNameTuple(member) 1252 type = info[0] 1253 name = info[1] 1254 cdecl = self.makeCParamDecl(member, 0) 1255 # Process VkStructureType 1256 if type == 'VkStructureType': 1257 # Extract the required struct type value from the comments 1258 # embedded in the original text defining the 'typeinfo' element 1259 rawXml = etree.tostring(typeinfo.elem).decode('ascii') 1260 result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml) 1261 if result: 1262 value = result.group(0) 1263 else: 1264 value = self.genVkStructureType(typeName) 1265 # Store the required type value 1266 self.structTypes[typeName] = self.StructType(name=name, value=value) 1267 # Store pointer/array/string info 1268 extstructs = self.registry.validextensionstructs[typeName] if name == 'pNext' else None 1269 membersInfo.append(self.CommandParam(type=type, 1270 name=name, 1271 ispointer=self.paramIsPointer(member), 1272 isconst=True if 'const' in cdecl else False, 1273 iscount=True if name in lens else False, 1274 len=self.getLen(member), 1275 extstructs=extstructs, 1276 cdecl=cdecl, 1277 islocal=False, 1278 iscreate=False, 1279 isdestroy=False, 1280 feature_protect=self.featureExtraProtect)) 1281 self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo)) 1282 1283 # 1284 # Determine if a struct has an NDO as a member or an embedded member 1285 def struct_contains_ndo(self, struct_item): 1286 struct_member_dict = dict(self.structMembers) 1287 struct_members = struct_member_dict[struct_item] 1288 1289 for member in struct_members: 1290 if self.handle_types.IsNonDispatchable(member.type): 1291 return True 1292 elif member.type in struct_member_dict: 1293 if self.struct_contains_ndo(member.type) == True: 1294 return True 1295 return False 1296 # 1297 # Return list of struct members which contain, or which sub-structures contain 1298 # an NDO in a given list of parameters or members 1299 def getParmeterStructsWithNdos(self, item_list): 1300 struct_list = set() 1301 for item in item_list: 1302 paramtype = item.find('type') 1303 typecategory = self.type_categories[paramtype.text] 1304 if typecategory == 'struct': 1305 if self.struct_contains_ndo(paramtype.text) == True: 1306 struct_list.add(item) 1307 return struct_list 1308 # 1309 # Return list of non-dispatchable objects from a given list of parameters or members 1310 def getNdosInParameterList(self, item_list, create_func): 1311 ndo_list = set() 1312 if create_func == True: 1313 member_list = item_list[0:-1] 1314 else: 1315 member_list = item_list 1316 for item in member_list: 1317 if self.handle_types.IsNonDispatchable(paramtype.text): 1318 ndo_list.add(item) 1319 return ndo_list 1320 # 1321 # Construct list of extension structs containing handles, or extension structs that share a structextends attribute 1322 # WITH an extension struct containing handles. All extension structs in any pNext chain will have to be copied. 1323 # TODO: make this recursive -- structs buried three or more levels deep are not searched for extensions 1324 def GenerateCommandWrapExtensionList(self): 1325 for struct in self.structMembers: 1326 if (len(struct.members) > 1) and struct.members[1].extstructs is not None: 1327 found = False; 1328 for item in struct.members[1].extstructs: 1329 if item != '' and item not in self.pnext_extension_structs: 1330 self.pnext_extension_structs.append(item) 1331 if item != '' and self.struct_contains_ndo(item) == True: 1332 found = True 1333 if found == True: 1334 for item in struct.members[1].extstructs: 1335 if item != '' and item not in self.extension_structs: 1336 self.extension_structs.append(item) 1337 # 1338 # Returns True if a struct may have a pNext chain containing an NDO 1339 def StructWithExtensions(self, struct_type): 1340 if struct_type in self.struct_member_dict: 1341 param_info = self.struct_member_dict[struct_type] 1342 if (len(param_info) > 1) and param_info[1].extstructs is not None: 1343 for item in param_info[1].extstructs: 1344 if item in self.extension_structs: 1345 return True 1346 return False 1347 # 1348 # Generate pNext handling function 1349 def build_extension_processing_func(self): 1350 # Construct helper functions to build and free pNext extension chains 1351 pnext_proc = '' 1352 pnext_proc += 'void WrapPnextChainHandles(ValidationObject *layer_data, const void *pNext) {\n' 1353 pnext_proc += ' void *cur_pnext = const_cast<void *>(pNext);\n' 1354 pnext_proc += ' while (cur_pnext != NULL) {\n' 1355 pnext_proc += ' VkBaseOutStructure *header = reinterpret_cast<VkBaseOutStructure *>(cur_pnext);\n\n' 1356 pnext_proc += ' switch (header->sType) {\n' 1357 for item in self.pnext_extension_structs: 1358 struct_info = self.struct_member_dict[item] 1359 indent = ' ' 1360 (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, 'safe_struct->', 0, False, False, False, False) 1361 # Only process extension structs containing handles 1362 if not tmp_pre: 1363 continue 1364 if struct_info[0].feature_protect is not None: 1365 pnext_proc += '#ifdef %s \n' % struct_info[0].feature_protect 1366 pnext_proc += ' case %s: {\n' % self.structTypes[item].value 1367 pnext_proc += ' safe_%s *safe_struct = reinterpret_cast<safe_%s *>(cur_pnext);\n' % (item, item) 1368 # Generate code to unwrap the handles 1369 pnext_proc += tmp_pre 1370 pnext_proc += ' } break;\n' 1371 if struct_info[0].feature_protect is not None: 1372 pnext_proc += '#endif // %s \n' % struct_info[0].feature_protect 1373 pnext_proc += '\n' 1374 pnext_proc += ' default:\n' 1375 pnext_proc += ' break;\n' 1376 pnext_proc += ' }\n\n' 1377 pnext_proc += ' // Process the next structure in the chain\n' 1378 pnext_proc += ' cur_pnext = header->pNext;\n' 1379 pnext_proc += ' }\n' 1380 pnext_proc += '}\n' 1381 return pnext_proc 1382 1383 # 1384 # Generate source for creating a non-dispatchable object 1385 def generate_create_ndo_code(self, indent, proto, params, cmd_info): 1386 create_ndo_code = '' 1387 handle_type = params[-1].find('type') 1388 if self.handle_types.IsNonDispatchable(handle_type.text): 1389 # Check for special case where multiple handles are returned 1390 ndo_array = False 1391 if cmd_info[-1].len is not None: 1392 ndo_array = True; 1393 handle_name = params[-1].find('name') 1394 create_ndo_code += '%sif (VK_SUCCESS == result) {\n' % (indent) 1395 indent = self.incIndent(indent) 1396 ndo_dest = '*%s' % handle_name.text 1397 if ndo_array == True: 1398 create_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[-1].len) 1399 indent = self.incIndent(indent) 1400 ndo_dest = '%s[index0]' % cmd_info[-1].name 1401 create_ndo_code += '%s%s = layer_data->WrapNew(%s);\n' % (indent, ndo_dest, ndo_dest) 1402 if ndo_array == True: 1403 indent = self.decIndent(indent) 1404 create_ndo_code += '%s}\n' % indent 1405 indent = self.decIndent(indent) 1406 create_ndo_code += '%s}\n' % (indent) 1407 return create_ndo_code 1408 # 1409 # Generate source for destroying a non-dispatchable object 1410 def generate_destroy_ndo_code(self, indent, proto, cmd_info): 1411 destroy_ndo_code = '' 1412 ndo_array = False 1413 if True in [destroy_txt in proto.text for destroy_txt in ['Destroy', 'Free']]: 1414 # Check for special case where multiple handles are returned 1415 if cmd_info[-1].len is not None: 1416 ndo_array = True; 1417 param = -1 1418 else: 1419 param = -2 1420 if self.handle_types.IsNonDispatchable(cmd_info[param].type): 1421 if ndo_array == True: 1422 # This API is freeing an array of handles. Remove them from the unique_id map. 1423 destroy_ndo_code += '%sif ((VK_SUCCESS == result) && (%s)) {\n' % (indent, cmd_info[param].name) 1424 indent = self.incIndent(indent) 1425 destroy_ndo_code += '%sfor (uint32_t index0 = 0; index0 < %s; index0++) {\n' % (indent, cmd_info[param].len) 1426 indent = self.incIndent(indent) 1427 destroy_ndo_code += '%s%s handle = %s[index0];\n' % (indent, cmd_info[param].type, cmd_info[param].name) 1428 destroy_ndo_code += '%suint64_t unique_id = reinterpret_cast<uint64_t &>(handle);\n' % (indent) 1429 destroy_ndo_code += '%sunique_id_mapping.erase(unique_id);\n' % (indent) 1430 indent = self.decIndent(indent); 1431 destroy_ndo_code += '%s}\n' % indent 1432 indent = self.decIndent(indent); 1433 destroy_ndo_code += '%s}\n' % indent 1434 else: 1435 # Remove a single handle from the map 1436 destroy_ndo_code += '%suint64_t %s_id = reinterpret_cast<uint64_t &>(%s);\n' % (indent, cmd_info[param].name, cmd_info[param].name) 1437 destroy_ndo_code += '%sauto iter = unique_id_mapping.pop(%s_id);\n' % (indent, cmd_info[param].name) 1438 destroy_ndo_code += '%sif (iter != unique_id_mapping.end()) {\n' % (indent) 1439 indent = self.incIndent(indent) 1440 destroy_ndo_code += '%s%s = (%s)iter->second;\n' % (indent, cmd_info[param].name, cmd_info[param].type) 1441 indent = self.decIndent(indent); 1442 destroy_ndo_code += '%s} else {\n' % (indent) 1443 indent = self.incIndent(indent) 1444 destroy_ndo_code += '%s%s = (%s)0;\n' % (indent, cmd_info[param].name, cmd_info[param].type) 1445 indent = self.decIndent(indent); 1446 destroy_ndo_code += '%s}\n' % (indent) 1447 1448 return ndo_array, destroy_ndo_code 1449 1450 # 1451 # Clean up local declarations 1452 def cleanUpLocalDeclarations(self, indent, prefix, name, len, index): 1453 cleanup = '%sif (local_%s%s) {\n' % (indent, prefix, name) 1454 if len is not None: 1455 cleanup += '%s delete[] local_%s%s;\n' % (indent, prefix, name) 1456 else: 1457 cleanup += '%s delete local_%s%s;\n' % (indent, prefix, name) 1458 cleanup += "%s}\n" % (indent) 1459 return cleanup 1460 # 1461 # Output UO code for a single NDO (ndo_count is NULL) or a counted list of NDOs 1462 def outputNDOs(self, ndo_type, ndo_name, ndo_count, prefix, index, indent, destroy_func, destroy_array, top_level): 1463 decl_code = '' 1464 pre_call_code = '' 1465 post_call_code = '' 1466 if ndo_count is not None: 1467 if top_level == True: 1468 decl_code += '%s%s *local_%s%s = NULL;\n' % (indent, ndo_type, prefix, ndo_name) 1469 pre_call_code += '%s if (%s%s) {\n' % (indent, prefix, ndo_name) 1470 indent = self.incIndent(indent) 1471 if top_level == True: 1472 pre_call_code += '%s local_%s%s = new %s[%s];\n' % (indent, prefix, ndo_name, ndo_type, ndo_count) 1473 pre_call_code += '%s for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, ndo_count, index) 1474 indent = self.incIndent(indent) 1475 pre_call_code += '%s local_%s%s[%s] = layer_data->Unwrap(%s[%s]);\n' % (indent, prefix, ndo_name, index, ndo_name, index) 1476 else: 1477 pre_call_code += '%s for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (indent, index, index, ndo_count, index) 1478 indent = self.incIndent(indent) 1479 pre_call_code += '%s %s%s[%s] = layer_data->Unwrap(%s%s[%s]);\n' % (indent, prefix, ndo_name, index, prefix, ndo_name, index) 1480 indent = self.decIndent(indent) 1481 pre_call_code += '%s }\n' % indent 1482 indent = self.decIndent(indent) 1483 pre_call_code += '%s }\n' % indent 1484 if top_level == True: 1485 post_call_code += '%sif (local_%s%s)\n' % (indent, prefix, ndo_name) 1486 indent = self.incIndent(indent) 1487 post_call_code += '%sdelete[] local_%s;\n' % (indent, ndo_name) 1488 else: 1489 if top_level == True: 1490 if (destroy_func == False) or (destroy_array == True): 1491 pre_call_code += '%s %s = layer_data->Unwrap(%s);\n' % (indent, ndo_name, ndo_name) 1492 else: 1493 # Make temp copy of this var with the 'local' removed. It may be better to not pass in 'local_' 1494 # as part of the string and explicitly print it 1495 fix = str(prefix).strip('local_'); 1496 pre_call_code += '%s if (%s%s) {\n' % (indent, fix, ndo_name) 1497 indent = self.incIndent(indent) 1498 pre_call_code += '%s %s%s = layer_data->Unwrap(%s%s);\n' % (indent, prefix, ndo_name, fix, ndo_name) 1499 indent = self.decIndent(indent) 1500 pre_call_code += '%s }\n' % indent 1501 return decl_code, pre_call_code, post_call_code 1502 # 1503 # first_level_param indicates if elements are passed directly into the function else they're below a ptr/struct 1504 # create_func means that this is API creates or allocates NDOs 1505 # destroy_func indicates that this API destroys or frees NDOs 1506 # destroy_array means that the destroy_func operated on an array of NDOs 1507 def uniquify_members(self, members, indent, prefix, array_index, create_func, destroy_func, destroy_array, first_level_param): 1508 decls = '' 1509 pre_code = '' 1510 post_code = '' 1511 index = 'index%s' % str(array_index) 1512 array_index += 1 1513 # Process any NDOs in this structure and recurse for any sub-structs in this struct 1514 for member in members: 1515 process_pnext = self.StructWithExtensions(member.type) 1516 # Handle NDOs 1517 if self.handle_types.IsNonDispatchable(member.type): 1518 count_name = member.len 1519 if (count_name is not None): 1520 if first_level_param == False: 1521 count_name = '%s%s' % (prefix, member.len) 1522 1523 if (first_level_param == False) or (create_func == False) or (not '*' in member.cdecl): 1524 (tmp_decl, tmp_pre, tmp_post) = self.outputNDOs(member.type, member.name, count_name, prefix, index, indent, destroy_func, destroy_array, first_level_param) 1525 decls += tmp_decl 1526 pre_code += tmp_pre 1527 post_code += tmp_post 1528 # Handle Structs that contain NDOs at some level 1529 elif member.type in self.struct_member_dict: 1530 # Structs at first level will have an NDO, OR, we need a safe_struct for the pnext chain 1531 if self.struct_contains_ndo(member.type) == True or process_pnext: 1532 struct_info = self.struct_member_dict[member.type] 1533 # TODO (jbolz): Can this use paramIsPointer? 1534 ispointer = '*' in member.cdecl; 1535 # Struct Array 1536 if member.len is not None: 1537 # Update struct prefix 1538 if first_level_param == True: 1539 new_prefix = 'local_%s' % member.name 1540 # Declare safe_VarType for struct 1541 decls += '%ssafe_%s *%s = NULL;\n' % (indent, member.type, new_prefix) 1542 else: 1543 new_prefix = '%s%s' % (prefix, member.name) 1544 pre_code += '%s if (%s%s) {\n' % (indent, prefix, member.name) 1545 indent = self.incIndent(indent) 1546 if first_level_param == True: 1547 pre_code += '%s %s = new safe_%s[%s];\n' % (indent, new_prefix, member.type, member.len) 1548 pre_code += '%s for (uint32_t %s = 0; %s < %s%s; ++%s) {\n' % (indent, index, index, prefix, member.len, index) 1549 indent = self.incIndent(indent) 1550 if first_level_param == True: 1551 pre_code += '%s %s[%s].initialize(&%s[%s]);\n' % (indent, new_prefix, index, member.name, index) 1552 if process_pnext: 1553 pre_code += '%s WrapPnextChainHandles(layer_data, %s[%s].pNext);\n' % (indent, new_prefix, index) 1554 local_prefix = '%s[%s].' % (new_prefix, index) 1555 # Process sub-structs in this struct 1556 (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, local_prefix, array_index, create_func, destroy_func, destroy_array, False) 1557 decls += tmp_decl 1558 pre_code += tmp_pre 1559 post_code += tmp_post 1560 indent = self.decIndent(indent) 1561 pre_code += '%s }\n' % indent 1562 indent = self.decIndent(indent) 1563 pre_code += '%s }\n' % indent 1564 if first_level_param == True: 1565 post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len, index) 1566 # Single Struct 1567 elif ispointer: 1568 # Update struct prefix 1569 if first_level_param == True: 1570 new_prefix = 'local_%s->' % member.name 1571 decls += '%ssafe_%s *local_%s%s = NULL;\n' % (indent, member.type, prefix, member.name) 1572 else: 1573 new_prefix = '%s%s->' % (prefix, member.name) 1574 # Declare safe_VarType for struct 1575 pre_code += '%s if (%s%s) {\n' % (indent, prefix, member.name) 1576 indent = self.incIndent(indent) 1577 if first_level_param == True: 1578 pre_code += '%s local_%s%s = new safe_%s(%s);\n' % (indent, prefix, member.name, member.type, member.name) 1579 # Process sub-structs in this struct 1580 (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, False) 1581 decls += tmp_decl 1582 pre_code += tmp_pre 1583 post_code += tmp_post 1584 if process_pnext: 1585 pre_code += '%s WrapPnextChainHandles(layer_data, local_%s%s->pNext);\n' % (indent, prefix, member.name) 1586 indent = self.decIndent(indent) 1587 pre_code += '%s }\n' % indent 1588 if first_level_param == True: 1589 post_code += self.cleanUpLocalDeclarations(indent, prefix, member.name, member.len, index) 1590 else: 1591 # Update struct prefix 1592 if first_level_param == True: 1593 sys.exit(1) 1594 else: 1595 new_prefix = '%s%s.' % (prefix, member.name) 1596 # Process sub-structs in this struct 1597 (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, new_prefix, array_index, create_func, destroy_func, destroy_array, False) 1598 decls += tmp_decl 1599 pre_code += tmp_pre 1600 post_code += tmp_post 1601 if process_pnext: 1602 pre_code += '%s WrapPnextChainHandles(layer_data, local_%s%s.pNext);\n' % (indent, prefix, member.name) 1603 return decls, pre_code, post_code 1604 # 1605 # For a particular API, generate the non-dispatchable-object wrapping/unwrapping code 1606 def generate_wrapping_code(self, cmd): 1607 indent = ' ' 1608 proto = cmd.find('proto/name') 1609 params = cmd.findall('param') 1610 1611 if proto.text is not None: 1612 cmd_member_dict = dict(self.cmdMembers) 1613 cmd_info = cmd_member_dict[proto.text] 1614 # Handle ndo create/allocate operations 1615 if cmd_info[0].iscreate: 1616 create_ndo_code = self.generate_create_ndo_code(indent, proto, params, cmd_info) 1617 else: 1618 create_ndo_code = '' 1619 # Handle ndo destroy/free operations 1620 if cmd_info[0].isdestroy: 1621 (destroy_array, destroy_ndo_code) = self.generate_destroy_ndo_code(indent, proto, cmd_info) 1622 else: 1623 destroy_array = False 1624 destroy_ndo_code = '' 1625 paramdecl = '' 1626 param_pre_code = '' 1627 param_post_code = '' 1628 create_func = True if create_ndo_code else False 1629 destroy_func = True if destroy_ndo_code else False 1630 (paramdecl, param_pre_code, param_post_code) = self.uniquify_members(cmd_info, indent, '', 0, create_func, destroy_func, destroy_array, True) 1631 param_post_code += create_ndo_code 1632 if destroy_ndo_code: 1633 if destroy_array == True: 1634 param_post_code += destroy_ndo_code 1635 else: 1636 param_pre_code += destroy_ndo_code 1637 if param_pre_code: 1638 if (not destroy_func) or (destroy_array): 1639 param_pre_code = '%s{\n%s%s}\n' % (' ', param_pre_code, indent) 1640 return paramdecl, param_pre_code, param_post_code 1641 # 1642 # Capture command parameter info needed to wrap NDOs as well as handling some boilerplate code 1643 def genCmd(self, cmdinfo, cmdname, alias): 1644 1645 # Add struct-member type information to command parameter information 1646 OutputGenerator.genCmd(self, cmdinfo, cmdname, alias) 1647 members = cmdinfo.elem.findall('.//param') 1648 # Iterate over members once to get length parameters for arrays 1649 lens = set() 1650 for member in members: 1651 len = self.getLen(member) 1652 if len: 1653 lens.add(len) 1654 struct_member_dict = dict(self.structMembers) 1655 # Generate member info 1656 membersInfo = [] 1657 for member in members: 1658 # Get type and name of member 1659 info = self.getTypeNameTuple(member) 1660 type = info[0] 1661 name = info[1] 1662 cdecl = self.makeCParamDecl(member, 0) 1663 # Check for parameter name in lens set 1664 iscount = True if name in lens else False 1665 len = self.getLen(member) 1666 isconst = True if 'const' in cdecl else False 1667 ispointer = self.paramIsPointer(member) 1668 # Mark param as local if it is an array of NDOs 1669 islocal = False; 1670 if self.handle_types.IsNonDispatchable(type): 1671 if (len is not None) and (isconst == True): 1672 islocal = True 1673 # Or if it's a struct that contains an NDO 1674 elif type in struct_member_dict: 1675 if self.struct_contains_ndo(type) == True: 1676 islocal = True 1677 isdestroy = True if True in [destroy_txt in cmdname for destroy_txt in ['Destroy', 'Free']] else False 1678 iscreate = True if True in [create_txt in cmdname for create_txt in ['Create', 'Allocate', 'GetRandROutputDisplayEXT', 'RegisterDeviceEvent', 'RegisterDisplayEvent']] else False 1679 extstructs = self.registry.validextensionstructs[type] if name == 'pNext' else None 1680 membersInfo.append(self.CommandParam(type=type, 1681 name=name, 1682 ispointer=ispointer, 1683 isconst=isconst, 1684 iscount=iscount, 1685 len=len, 1686 extstructs=extstructs, 1687 cdecl=cdecl, 1688 islocal=islocal, 1689 iscreate=iscreate, 1690 isdestroy=isdestroy, 1691 feature_protect=self.featureExtraProtect)) 1692 self.cmdMembers.append(self.CmdMemberData(name=cmdname, members=membersInfo)) 1693 self.cmd_info_data.append(self.CmdInfoData(name=cmdname, cmdinfo=cmdinfo)) 1694 self.cmd_feature_protect.append(self.CmdExtraProtect(name=cmdname, extra_protect=self.featureExtraProtect)) 1695 # 1696 # Create prototype for dispatch header file 1697 def GenDispatchFunctionPrototype(self, cmdinfo, ifdef_text): 1698 decls = self.makeCDecls(cmdinfo.elem) 1699 func_sig = decls[0][:-1] 1700 func_sig = func_sig.replace("VKAPI_ATTR ", "") 1701 func_sig = func_sig.replace("VKAPI_CALL ", "Dispatch") 1702 func_sig += ';' 1703 dispatch_prototype = '' 1704 if ifdef_text is not None: 1705 dispatch_prototype = '#ifdef %s\n' % ifdef_text 1706 dispatch_prototype += func_sig 1707 if ifdef_text is not None: 1708 dispatch_prototype += '\n#endif // %s' % ifdef_text 1709 return dispatch_prototype 1710 # 1711 # Create code to wrap NDOs as well as handling some boilerplate code 1712 def WrapCommands(self): 1713 cmd_member_dict = dict(self.cmdMembers) 1714 cmd_info_dict = dict(self.cmd_info_data) 1715 cmd_protect_dict = dict(self.cmd_feature_protect) 1716 1717 for api_call in self.cmdMembers: 1718 cmdname = api_call.name 1719 cmdinfo = cmd_info_dict[api_call.name] 1720 feature_extra_protect = cmd_protect_dict[api_call.name] 1721 1722 # Add fuction prototype to header data 1723 self.appendSection('header_file', self.GenDispatchFunctionPrototype(cmdinfo, feature_extra_protect)) 1724 1725 if cmdname in self.no_autogen_list: 1726 decls = self.makeCDecls(cmdinfo.elem) 1727 self.appendSection('source_file', '') 1728 self.appendSection('source_file', '// Skip %s dispatch, manually generated' % cmdname) 1729 continue 1730 1731 # Generate NDO wrapping/unwrapping code for all parameters 1732 (api_decls, api_pre, api_post) = self.generate_wrapping_code(cmdinfo.elem) 1733 # If API doesn't contain NDO's, we still need to make a down-chain call 1734 down_chain_call_only = False 1735 if not api_decls and not api_pre and not api_post: 1736 down_chain_call_only = True 1737 if (feature_extra_protect is not None): 1738 self.appendSection('source_file', '') 1739 self.appendSection('source_file', '#ifdef ' + feature_extra_protect) 1740 1741 decls = self.makeCDecls(cmdinfo.elem) 1742 func_sig = decls[0][:-1] 1743 func_sig = func_sig.replace("VKAPI_ATTR ", "") 1744 func_sig = func_sig.replace("VKAPI_CALL ", "Dispatch") 1745 self.appendSection('source_file', '') 1746 self.appendSection('source_file', func_sig) 1747 self.appendSection('source_file', '{') 1748 # Setup common to call wrappers, first parameter is always dispatchable 1749 dispatchable_type = cmdinfo.elem.find('param/type').text 1750 dispatchable_name = cmdinfo.elem.find('param/name').text 1751 1752 # Gather the parameter items 1753 params = cmdinfo.elem.findall('param/name') 1754 # Pull out the text for each of the parameters, separate them by commas in a list 1755 paramstext = ', '.join([str(param.text) for param in params]) 1756 wrapped_paramstext = paramstext 1757 # If any of these paramters has been replaced by a local var, fix up the list 1758 params = cmd_member_dict[cmdname] 1759 for param in params: 1760 if param.islocal == True or self.StructWithExtensions(param.type): 1761 if param.ispointer == True: 1762 wrapped_paramstext = wrapped_paramstext.replace(param.name, '(%s %s*)local_%s' % ('const', param.type, param.name)) 1763 else: 1764 wrapped_paramstext = wrapped_paramstext.replace(param.name, '(%s %s)local_%s' % ('const', param.type, param.name)) 1765 1766 # First, add check and down-chain call. Use correct dispatch table 1767 dispatch_table_type = "device_dispatch_table" 1768 if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]: 1769 dispatch_table_type = "instance_dispatch_table" 1770 1771 api_func = cmdinfo.elem.attrib.get('name').replace('vk','layer_data->%s.',1) % dispatch_table_type 1772 # Call to get the layer_data pointer 1773 self.appendSection('source_file', ' auto layer_data = GetLayerDataPtr(get_dispatch_key(%s), layer_data_map);' % dispatchable_name) 1774 # Put all this together for the final down-chain call 1775 if not down_chain_call_only: 1776 unwrapped_dispatch_call = api_func + '(' + paramstext + ')' 1777 self.appendSection('source_file', ' if (!wrap_handles) return %s;' % unwrapped_dispatch_call) 1778 1779 # Handle return values, if any 1780 resulttype = cmdinfo.elem.find('proto/type') 1781 if (resulttype is not None and resulttype.text == 'void'): 1782 resulttype = None 1783 if (resulttype is not None): 1784 assignresult = resulttype.text + ' result = ' 1785 else: 1786 assignresult = '' 1787 # Pre-pend declarations and pre-api-call codegen 1788 if api_decls: 1789 self.appendSection('source_file', "\n".join(str(api_decls).rstrip().split("\n"))) 1790 if api_pre: 1791 self.appendSection('source_file', "\n".join(str(api_pre).rstrip().split("\n"))) 1792 # Generate the wrapped dispatch call 1793 self.appendSection('source_file', ' ' + assignresult + api_func + '(' + wrapped_paramstext + ');') 1794 1795 # And add the post-API-call codegen 1796 self.appendSection('source_file', "\n".join(str(api_post).rstrip().split("\n"))) 1797 # Handle the return result variable, if any 1798 if (resulttype is not None): 1799 self.appendSection('source_file', ' return result;') 1800 self.appendSection('source_file', '}') 1801 if (feature_extra_protect is not None): 1802 self.appendSection('source_file', '#endif // '+ feature_extra_protect) 1803 1804