• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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