layers: Fix Graphics Pipeline pointers not ignored
authorPetr Kraus <petr_kraus@email.cz>
Sun, 10 Sep 2017 00:26:33 +0000 (02:26 +0200)
committerMark Lobodzinski <mark@lunarg.com>
Tue, 12 Sep 2017 14:35:17 +0000 (08:35 -0600)
Some VkGraphicsPipelineCreateInfo pointers must be ignored under some
conditions, but were not in the layers.

Add relevant tests.

Fix tests found broken (using depth or color without attachment in
subpass)

Change-Id: I3e2a3f61a52c72ce3a11483ff8b031189f4c61c9

layers/core_validation.cpp
layers/core_validation_types.h
layers/parameter_validation.h
layers/parameter_validation_utils.cpp
layers/unique_objects.cpp
layers/unique_objects.h
scripts/helper_file_generator.py
scripts/parameter_validation_generator.py
scripts/unique_objects_generator.py

index 78e72aa..b210f8f 100644 (file)
@@ -4514,8 +4514,8 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipeli
 
     for (i = 0; i < count; i++) {
         pipe_state.push_back(std::unique_ptr<PIPELINE_STATE>(new PIPELINE_STATE));
-        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
         pipe_state[i]->render_pass_ci.initialize(GetRenderPassState(dev_data, pCreateInfos[i].renderPass)->createInfo.ptr());
+        pipe_state[i]->initGraphicsPipeline(&pCreateInfos[i]);
         pipe_state[i]->pipeline_layout = *getPipelineLayout(dev_data, pCreateInfos[i].layout);
     }
 
index 928583c..610539a 100644 (file)
@@ -576,7 +576,23 @@ class PIPELINE_STATE : public BASE_NODE {
           pipeline_layout() {}
 
     void initGraphicsPipeline(const VkGraphicsPipelineCreateInfo *pCreateInfo) {
-        graphicsPipelineCI.initialize(pCreateInfo);
+        bool uses_color_attachment = false;
+        bool uses_depthstencil_attachment = false;
+        if (pCreateInfo->subpass < render_pass_ci.subpassCount) {
+            const auto &subpass = render_pass_ci.pSubpasses[pCreateInfo->subpass];
+
+            for (uint32_t i = 0; i < subpass.colorAttachmentCount; ++i) {
+                if (subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
+                    uses_color_attachment = true;
+                    break;
+                }
+            }
+
+            if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
+                uses_depthstencil_attachment = true;
+            }
+        }
+        graphicsPipelineCI.initialize(pCreateInfo, uses_color_attachment, uses_depthstencil_attachment);
         // Make sure compute pipeline is null
         VkComputePipelineCreateInfo emptyComputeCI = {};
         computePipelineCI.initialize(&emptyComputeCI);
@@ -585,15 +601,15 @@ class PIPELINE_STATE : public BASE_NODE {
             this->duplicate_shaders |= this->active_shaders & pPSSCI->stage;
             this->active_shaders |= pPSSCI->stage;
         }
-        if (pCreateInfo->pVertexInputState) {
-            const VkPipelineVertexInputStateCreateInfo *pVICI = pCreateInfo->pVertexInputState;
+        if (graphicsPipelineCI.pVertexInputState) {
+            const auto pVICI = graphicsPipelineCI.pVertexInputState;
             if (pVICI->vertexBindingDescriptionCount) {
                 this->vertexBindingDescriptions = std::vector<VkVertexInputBindingDescription>(
                     pVICI->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions + pVICI->vertexBindingDescriptionCount);
             }
         }
-        if (pCreateInfo->pColorBlendState) {
-            const VkPipelineColorBlendStateCreateInfo *pCBCI = pCreateInfo->pColorBlendState;
+        if (graphicsPipelineCI.pColorBlendState) {
+            const auto pCBCI = graphicsPipelineCI.pColorBlendState;
             if (pCBCI->attachmentCount) {
                 this->attachments = std::vector<VkPipelineColorBlendAttachmentState>(pCBCI->pAttachments,
                                                                                      pCBCI->pAttachments + pCBCI->attachmentCount);
@@ -605,7 +621,7 @@ class PIPELINE_STATE : public BASE_NODE {
         computePipelineCI.initialize(pCreateInfo);
         // Make sure gfx pipeline is null
         VkGraphicsPipelineCreateInfo emptyGraphicsCI = {};
-        graphicsPipelineCI.initialize(&emptyGraphicsCI);
+        graphicsPipelineCI.initialize(&emptyGraphicsCI, false, false);
         switch (computePipelineCI.stage.stage) {
             case VK_SHADER_STAGE_COMPUTE_BIT:
                 this->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT;
index 6ef3de2..b9d153c 100644 (file)
@@ -25,8 +25,9 @@
 #include <cstdlib>
 #include <string>
 #include <bitset>
-#include <mutex>
+#include <unordered_map>
 #include <unordered_set>
+#include <mutex>
 
 #include "vulkan/vulkan.h"
 #include "vk_enum_string_helper.h"
@@ -80,6 +81,13 @@ struct layer_data {
     VkDevice device = VK_NULL_HANDLE;
     DeviceExtensions extensions;
 
+    struct SubpassesUsageStates {
+        std::unordered_set<uint32_t> subpasses_using_color_attachment;
+        std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
+    };
+
+    std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
+
     VkLayerDispatchTable dispatch_table = {};
 };
 
index 4f6f5b8..11706cd 100644 (file)
@@ -82,6 +82,10 @@ extern bool parameter_validation_vkDestroyDebugReportCallbackEXT(VkInstance inst
                                                                  const VkAllocationCallbacks *pAllocator);
 extern bool parameter_validation_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
                                                      const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool);
+extern bool parameter_validation_vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                    const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+extern bool parameter_validation_vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass,
+                                                     const VkAllocationCallbacks *pAllocator);
 
 // TODO : This can be much smarter, using separate locks for separate global data
 std::mutex global_lock;
@@ -590,6 +594,78 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryP
     return result;
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                  const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+    VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= parameter_validation_vkCreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
+
+        typedef bool (*PFN_manual_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                      const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+        PFN_manual_vkCreateRenderPass custom_func = (PFN_manual_vkCreateRenderPass)custom_functions["vkCreateRenderPass"];
+        if (custom_func != nullptr) {
+            skip |= custom_func(device, pCreateInfo, pAllocator, pRenderPass);
+        }
+    }
+
+    if (!skip) {
+        result = device_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
+
+        // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
+        if (result == VK_SUCCESS) {
+            std::unique_lock<std::mutex> lock(global_lock);
+            const auto renderPass = *pRenderPass;
+            auto &renderpass_state = device_data->renderpasses_states[renderPass];
+
+            for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
+                bool uses_color = false;
+                for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
+                    if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
+
+                bool uses_depthstencil = false;
+                if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
+                    if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
+                        uses_depthstencil = true;
+
+                if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
+                if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
+            }
+        }
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
+    layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    bool skip = false;
+
+    {
+        std::unique_lock<std::mutex> lock(global_lock);
+        skip |= parameter_validation_vkDestroyRenderPass(device, renderPass, pAllocator);
+
+        typedef bool (*PFN_manual_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass,
+                                                       const VkAllocationCallbacks *pAllocator);
+        PFN_manual_vkDestroyRenderPass custom_func = (PFN_manual_vkDestroyRenderPass)custom_functions["vkDestroyRenderPass"];
+        if (custom_func != nullptr) {
+            skip |= custom_func(device, renderPass, pAllocator);
+        }
+    }
+
+    if (!skip) {
+        device_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
+
+        // track the state necessary for checking vkCreateGraphicsPipeline (subpass usage of depth and color attachments)
+        {
+            std::unique_lock<std::mutex> lock(global_lock);
+            device_data->renderpasses_states.erase(renderPass);
+        }
+    }
+}
+
 bool pv_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
                        VkBuffer *pBuffer) {
     bool skip = false;
@@ -1207,8 +1283,20 @@ bool pv_vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache
                     }
                 }
 
-                // TODO: Conditional NULL check based on subpass depth/stencil attachment
-                if (pCreateInfos[i].pDepthStencilState != nullptr) {
+                bool uses_color_attachment = false;
+                bool uses_depthstencil_attachment = false;
+                {
+                    const auto subpasses_uses_it = device_data->renderpasses_states.find(pCreateInfos[i].renderPass);
+                    if (subpasses_uses_it != device_data->renderpasses_states.end()) {
+                        const auto &subpasses_uses = subpasses_uses_it->second;
+                        if (subpasses_uses.subpasses_using_color_attachment.count(pCreateInfos[i].subpass))
+                            uses_color_attachment = true;
+                        if (subpasses_uses.subpasses_using_depthstencil_attachment.count(pCreateInfos[i].subpass))
+                            uses_depthstencil_attachment = true;
+                    }
+                }
+
+                if (pCreateInfos[i].pDepthStencilState != nullptr && uses_depthstencil_attachment) {
                     skip |= validate_struct_pnext(
                         report_data, "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pDepthStencilState->pNext", ParameterName::IndexVector{i}), NULL,
@@ -1302,8 +1390,7 @@ bool pv_vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache
                     }
                 }
 
-                // TODO: Conditional NULL check based on subpass color attachment
-                if (pCreateInfos[i].pColorBlendState != nullptr) {
+                if (pCreateInfos[i].pColorBlendState != nullptr && uses_color_attachment) {
                     skip |= validate_struct_pnext(
                         report_data, "vkCreateGraphicsPipelines",
                         ParameterName("pCreateInfos[%i].pColorBlendState->pNext", ParameterName::IndexVector{i}), NULL,
index d324ce4..8af7772 100644 (file)
@@ -328,7 +328,22 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipeli
         local_pCreateInfos = new safe_VkGraphicsPipelineCreateInfo[createInfoCount];
         std::lock_guard<std::mutex> lock(global_lock);
         for (uint32_t idx0 = 0; idx0 < createInfoCount; ++idx0) {
-            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0]);
+            bool uses_color_attachment = false;
+            bool uses_depthstencil_attachment = false;
+            {
+                const auto subpasses_uses_it =
+                    device_data->renderpasses_states.find(Unwrap(device_data, pCreateInfos[idx0].renderPass));
+                if (subpasses_uses_it != device_data->renderpasses_states.end()) {
+                    const auto &subpasses_uses = subpasses_uses_it->second;
+                    if (subpasses_uses.subpasses_using_color_attachment.count(pCreateInfos[idx0].subpass))
+                        uses_color_attachment = true;
+                    if (subpasses_uses.subpasses_using_depthstencil_attachment.count(pCreateInfos[idx0].subpass))
+                        uses_depthstencil_attachment = true;
+                }
+            }
+
+            local_pCreateInfos[idx0].initialize(&pCreateInfos[idx0], uses_color_attachment, uses_depthstencil_attachment);
+
             if (pCreateInfos[idx0].basePipelineHandle) {
                 local_pCreateInfos[idx0].basePipelineHandle = Unwrap(device_data, pCreateInfos[idx0].basePipelineHandle);
             }
@@ -366,6 +381,55 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateGraphicsPipelines(VkDevice device, VkPipeli
     return result;
 }
 
+static void PostCallCreateRenderPass(layer_data *dev_data, const VkRenderPassCreateInfo *pCreateInfo, VkRenderPass renderPass) {
+    auto &renderpass_state = dev_data->renderpasses_states[renderPass];
+
+    for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
+        bool uses_color = false;
+        for (uint32_t i = 0; i < pCreateInfo->pSubpasses[subpass].colorAttachmentCount && !uses_color; ++i)
+            if (pCreateInfo->pSubpasses[subpass].pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) uses_color = true;
+
+        bool uses_depthstencil = false;
+        if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment)
+            if (pCreateInfo->pSubpasses[subpass].pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
+                uses_depthstencil = true;
+
+        if (uses_color) renderpass_state.subpasses_using_color_attachment.insert(subpass);
+        if (uses_depthstencil) renderpass_state.subpasses_using_depthstencil_attachment.insert(subpass);
+    }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL CreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
+                                                const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    VkResult result = dev_data->dispatch_table.CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
+    if (VK_SUCCESS == result) {
+        std::lock_guard<std::mutex> lock(global_lock);
+
+        PostCallCreateRenderPass(dev_data, pCreateInfo, *pRenderPass);
+
+        *pRenderPass = WrapNew(dev_data, *pRenderPass);
+    }
+    return result;
+}
+
+static void PostCallDestroyRenderPass(layer_data *dev_data, VkRenderPass renderPass) {
+    dev_data->renderpasses_states.erase(renderPass);
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
+    layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+    std::unique_lock<std::mutex> lock(global_lock);
+    uint64_t renderPass_id = reinterpret_cast<uint64_t &>(renderPass);
+    renderPass = (VkRenderPass)dev_data->unique_id_mapping[renderPass_id];
+    dev_data->unique_id_mapping.erase(renderPass_id);
+    lock.unlock();
+    dev_data->dispatch_table.DestroyRenderPass(device, renderPass, pAllocator);
+
+    lock.lock();
+    PostCallDestroyRenderPass(dev_data, renderPass);
+}
+
 VKAPI_ATTR VkResult VKAPI_CALL CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
                                                   const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) {
     layer_data *my_map_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
index 57b9dbf..e604e91 100644 (file)
@@ -21,6 +21,9 @@
 
 #include "vulkan/vulkan.h"
 
+#include <unordered_map>
+#include <unordered_set>
+
 #include "vk_layer_data.h"
 #include "vk_safe_struct.h"
 #include "vk_layer_utils.h"
@@ -69,6 +72,13 @@ struct layer_data {
     std::unordered_map<uint64_t, uint64_t> unique_id_mapping;  // Map uniqueID to actual object handle
     VkPhysicalDevice gpu;
 
+    struct SubpassesUsageStates {
+        std::unordered_set<uint32_t> subpasses_using_color_attachment;
+        std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
+    };
+    // uses unwrapped handles
+    std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
+
     layer_data() : wsi_enabled(false), gpu(VK_NULL_HANDLE){};
 };
 
index a9d9390..de80951 100644 (file)
@@ -93,6 +93,15 @@ class HelperFileOutputGenerator(OutputGenerator):
         self.StructType = namedtuple('StructType', ['name', 'value'])
         self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl'])
         self.StructMemberData = namedtuple('StructMemberData', ['name', 'members', 'ifdef_protect'])
+
+        self.custom_construct_params = {
+            # safe_VkGraphicsPipelineCreateInfo needs to know if subpass has color and\or depth\stencil attachments to use its pointers
+            'VkGraphicsPipelineCreateInfo' :
+                ', const bool uses_color_attachment, const bool uses_depthstencil_attachment',
+            # safe_VkPipelineViewportStateCreateInfo needs to know if viewport and scissor is dynamic to use its pointers
+            'VkPipelineViewportStateCreateInfo' :
+                ', const bool is_dynamic_viewports, const bool is_dynamic_scissors',
+        }
     #
     # Called once at the beginning of each run
     def beginFile(self, genOpts):
@@ -557,12 +566,12 @@ class HelperFileOutputGenerator(OutputGenerator):
                             safe_struct_header += '    %s* %s;\n' % (member.type, member.name)
                     else:
                         safe_struct_header += '%s;\n' % member.cdecl
-                safe_struct_header += '    safe_%s(const %s* in_struct);\n' % (item.name, item.name)
-                safe_struct_header += '    safe_%s(const safe_%s& src);\n' % (item.name, item.name)
+                safe_struct_header += '    safe_%s(const %s* in_struct%s);\n' % (item.name, item.name, self.custom_construct_params.get(item.name, ''))
+                safe_struct_header += '    safe_%s(const safe_%s& src%s);\n' % (item.name, item.name, self.custom_construct_params.get(item.name, ''))
                 safe_struct_header += '    safe_%s();\n' % item.name
                 safe_struct_header += '    ~safe_%s();\n' % item.name
-                safe_struct_header += '    void initialize(const %s* in_struct);\n' % item.name
-                safe_struct_header += '    void initialize(const safe_%s* src);\n' % item.name
+                safe_struct_header += '    void initialize(const %s* in_struct%s);\n' % (item.name, self.custom_construct_params.get(item.name, ''))
+                safe_struct_header += '    void initialize(const safe_%s* src%s);\n' % (item.name, self.custom_construct_params.get(item.name, ''))
                 safe_struct_header += '    %s *ptr() { return reinterpret_cast<%s *>(this); }\n' % (item.name, item.name)
                 safe_struct_header += '    %s const *ptr() const { return reinterpret_cast<%s const *>(this); }\n' % (item.name, item.name)
                 safe_struct_header += '};\n'
@@ -750,49 +759,129 @@ class HelperFileOutputGenerator(OutputGenerator):
             init_func_txt = ''      # Txt for initialize() function that takes struct ptr and inits members
             construct_txt = ''      # Body of constuctor as well as body of initialize() func following init_func_txt
             destruct_txt = ''
-            # VkWriteDescriptorSet is special case because pointers may be non-null but ignored
-            custom_construct_txt = {'VkWriteDescriptorSet' :
-                                    '    switch (descriptorType) {\n'
-                                    '        case VK_DESCRIPTOR_TYPE_SAMPLER:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:\n'
-                                    '        if (descriptorCount && in_struct->pImageInfo) {\n'
-                                    '            pImageInfo = new VkDescriptorImageInfo[descriptorCount];\n'
-                                    '            for (uint32_t i=0; i<descriptorCount; ++i) {\n'
-                                    '                pImageInfo[i] = in_struct->pImageInfo[i];\n'
-                                    '            }\n'
-                                    '        }\n'
-                                    '        break;\n'
-                                    '        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:\n'
-                                    '        if (descriptorCount && in_struct->pBufferInfo) {\n'
-                                    '            pBufferInfo = new VkDescriptorBufferInfo[descriptorCount];\n'
-                                    '            for (uint32_t i=0; i<descriptorCount; ++i) {\n'
-                                    '                pBufferInfo[i] = in_struct->pBufferInfo[i];\n'
-                                    '            }\n'
-                                    '        }\n'
-                                    '        break;\n'
-                                    '        case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:\n'
-                                    '        case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:\n'
-                                    '        if (descriptorCount && in_struct->pTexelBufferView) {\n'
-                                    '            pTexelBufferView = new VkBufferView[descriptorCount];\n'
-                                    '            for (uint32_t i=0; i<descriptorCount; ++i) {\n'
-                                    '                pTexelBufferView[i] = in_struct->pTexelBufferView[i];\n'
-                                    '            }\n'
-                                    '        }\n'
-                                    '        break;\n'
-                                    '        default:\n'
-                                    '        break;\n'
-                                    '    }\n',
-                                    'VkShaderModuleCreateInfo' :
-                                    '    if (in_struct->pCode) {\n'
-                                    '        pCode = reinterpret_cast<uint32_t *>(new uint8_t[codeSize]);\n'
-                                    '        memcpy((void *)pCode, (void *)in_struct->pCode, codeSize);\n'
-                                    '    }\n'}
+
+            custom_construct_txt = {
+                # VkWriteDescriptorSet is special case because pointers may be non-null but ignored
+                'VkWriteDescriptorSet' :
+                    '    switch (descriptorType) {\n'
+                    '        case VK_DESCRIPTOR_TYPE_SAMPLER:\n'
+                    '        case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:\n'
+                    '        case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:\n'
+                    '        case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:\n'
+                    '        case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:\n'
+                    '        if (descriptorCount && in_struct->pImageInfo) {\n'
+                    '            pImageInfo = new VkDescriptorImageInfo[descriptorCount];\n'
+                    '            for (uint32_t i=0; i<descriptorCount; ++i) {\n'
+                    '                pImageInfo[i] = in_struct->pImageInfo[i];\n'
+                    '            }\n'
+                    '        }\n'
+                    '        break;\n'
+                    '        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:\n'
+                    '        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:\n'
+                    '        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:\n'
+                    '        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:\n'
+                    '        if (descriptorCount && in_struct->pBufferInfo) {\n'
+                    '            pBufferInfo = new VkDescriptorBufferInfo[descriptorCount];\n'
+                    '            for (uint32_t i=0; i<descriptorCount; ++i) {\n'
+                    '                pBufferInfo[i] = in_struct->pBufferInfo[i];\n'
+                    '            }\n'
+                    '        }\n'
+                    '        break;\n'
+                    '        case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:\n'
+                    '        case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:\n'
+                    '        if (descriptorCount && in_struct->pTexelBufferView) {\n'
+                    '            pTexelBufferView = new VkBufferView[descriptorCount];\n'
+                    '            for (uint32_t i=0; i<descriptorCount; ++i) {\n'
+                    '                pTexelBufferView[i] = in_struct->pTexelBufferView[i];\n'
+                    '            }\n'
+                    '        }\n'
+                    '        break;\n'
+                    '        default:\n'
+                    '        break;\n'
+                    '    }\n',
+                    'VkShaderModuleCreateInfo' :
+                    '    if (in_struct->pCode) {\n'
+                    '        pCode = reinterpret_cast<uint32_t *>(new uint8_t[codeSize]);\n'
+                    '        memcpy((void *)pCode, (void *)in_struct->pCode, codeSize);\n'
+                    '    }\n',
+                # VkGraphicsPipelineCreateInfo is special case because its pointers may be non-null but ignored
+                'VkGraphicsPipelineCreateInfo' :
+                    '    if (stageCount && in_struct->pStages) {\n'
+                    '        pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n'
+                    '        for (uint32_t i=0; i<stageCount; ++i) {\n'
+                    '            pStages[i].initialize(&in_struct->pStages[i]);\n'
+                    '        }\n'
+                    '    }\n'
+                    '    if (in_struct->pVertexInputState)\n'
+                    '        pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(in_struct->pVertexInputState);\n'
+                    '    else\n'
+                    '        pVertexInputState = NULL;\n'
+                    '    if (in_struct->pInputAssemblyState)\n'
+                    '        pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(in_struct->pInputAssemblyState);\n'
+                    '    else\n'
+                    '        pInputAssemblyState = NULL;\n'
+                    '    bool has_tessellation_stage = false;\n'
+                    '    if (stageCount && pStages)\n'
+                    '        for (uint32_t i=0; i<stageCount && !has_tessellation_stage; ++i)\n'
+                    '            if (pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)\n'
+                    '                has_tessellation_stage = true;\n'
+                    '    if (in_struct->pTessellationState && has_tessellation_stage)\n'
+                    '        pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(in_struct->pTessellationState);\n'
+                    '    else\n'
+                    '        pTessellationState = NULL; // original pTessellationState pointer ignored\n'
+                    '    bool has_rasterization = in_struct->pRasterizationState ? !in_struct->pRasterizationState->rasterizerDiscardEnable : false;\n'
+                    '    if (in_struct->pViewportState && has_rasterization) {\n'
+                    '        bool is_dynamic_viewports = false;\n'
+                    '        bool is_dynamic_scissors = false;\n'
+                    '        if (in_struct->pDynamicState && in_struct->pDynamicState->pDynamicStates) {\n'
+                    '            for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_viewports; ++i)\n'
+                    '                if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_VIEWPORT)\n'
+                    '                    is_dynamic_viewports = true;\n'
+                    '            for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_scissors; ++i)\n'
+                    '                if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_SCISSOR)\n'
+                    '                    is_dynamic_scissors = true;\n'
+                    '        }\n'
+                    '        pViewportState = new safe_VkPipelineViewportStateCreateInfo(in_struct->pViewportState, is_dynamic_viewports, is_dynamic_scissors);\n'
+                    '    } else\n'
+                    '        pViewportState = NULL; // original pViewportState pointer ignored\n'
+                    '    if (in_struct->pRasterizationState)\n'
+                    '        pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(in_struct->pRasterizationState);\n'
+                    '    else\n'
+                    '        pRasterizationState = NULL;\n'
+                    '    if (in_struct->pMultisampleState && has_rasterization)\n'
+                    '        pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(in_struct->pMultisampleState);\n'
+                    '    else\n'
+                    '        pMultisampleState = NULL; // original pMultisampleState pointer ignored\n'
+                    '    // needs a tracked subpass state uses_depthstencil_attachment\n'
+                    '    if (in_struct->pDepthStencilState && has_rasterization && uses_depthstencil_attachment)\n'
+                    '        pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(in_struct->pDepthStencilState);\n'
+                    '    else\n'
+                    '        pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n'
+                    '    // needs a tracked subpass state usesColorAttachment\n'
+                    '    if (in_struct->pColorBlendState && has_rasterization && uses_color_attachment)\n'
+                    '        pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(in_struct->pColorBlendState);\n'
+                    '    else\n'
+                    '        pColorBlendState = NULL; // original pColorBlendState pointer ignored\n'
+                    '    if (in_struct->pDynamicState)\n'
+                    '        pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(in_struct->pDynamicState);\n'
+                    '    else\n'
+                    '        pDynamicState = NULL;\n',
+                 # VkPipelineViewportStateCreateInfo is special case because its pointers may be non-null but ignored
+                'VkPipelineViewportStateCreateInfo' :
+                    '    if (in_struct->pViewports && !is_dynamic_viewports) {\n'
+                    '        pViewports = new VkViewport[in_struct->viewportCount];\n'
+                    '        memcpy ((void *)pViewports, (void *)in_struct->pViewports, sizeof(VkViewport)*in_struct->viewportCount);\n'
+                    '    }\n'
+                    '    else\n'
+                    '        pViewports = NULL;\n'
+                    '    if (in_struct->pScissors && !is_dynamic_scissors) {\n'
+                    '        pScissors = new VkRect2D[in_struct->scissorCount];\n'
+                    '        memcpy ((void *)pScissors, (void *)in_struct->pScissors, sizeof(VkRect2D)*in_struct->scissorCount);\n'
+                    '    }\n'
+                    '    else\n'
+                    '        pScissors = NULL;\n',
+            }
+
             custom_destruct_txt = {'VkShaderModuleCreateInfo' :
                                    '    if (pCode)\n'
                                    '        delete[] reinterpret_cast<const uint8_t *>(pCode);\n' }
@@ -874,7 +963,7 @@ class HelperFileOutputGenerator(OutputGenerator):
                 construct_txt = custom_construct_txt[item.name]
             if item.name in custom_destruct_txt:
                 destruct_txt = custom_destruct_txt[item.name]
-            safe_struct_body.append("\n%s::%s(const %s* in_struct) :%s\n{\n%s}" % (ss_name, ss_name, item.name, init_list, construct_txt))
+            safe_struct_body.append("\n%s::%s(const %s* in_struct%s) :%s\n{\n%s}" % (ss_name, ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_list, construct_txt))
             if '' != default_init_list:
                 default_init_list = " :%s" % (default_init_list[:-1])
             safe_struct_body.append("\n%s::%s()%s\n{}" % (ss_name, ss_name, default_init_list))
@@ -883,13 +972,13 @@ class HelperFileOutputGenerator(OutputGenerator):
             copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.')     # Exclude 'if' blocks from next line
             copy_construct_txt = copy_construct_txt.replace('(in_struct->', '(*src.') # Pass object to copy constructors
             copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.')    # Modify remaining struct refs for src object
-            safe_struct_body.append("\n%s::%s(const %s& src)\n{\n%s%s}" % (ss_name, ss_name, ss_name, copy_construct_init, copy_construct_txt)) # Copy constructor
+            safe_struct_body.append("\n%s::%s(const %s& src%s)\n{\n%s%s}" % (ss_name, ss_name, ss_name, self.custom_construct_params.get(item.name, ''), copy_construct_init, copy_construct_txt)) # Copy constructor
             safe_struct_body.append("\n%s::~%s()\n{\n%s}" % (ss_name, ss_name, destruct_txt))
-            safe_struct_body.append("\nvoid %s::initialize(const %s* in_struct)\n{\n%s%s}" % (ss_name, item.name, init_func_txt, construct_txt))
+            safe_struct_body.append("\nvoid %s::initialize(const %s* in_struct%s)\n{\n%s%s}" % (ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_func_txt, construct_txt))
             # Copy initializer uses same txt as copy constructor but has a ptr and not a reference
             init_copy = copy_construct_init.replace('src.', 'src->')
             init_construct = copy_construct_txt.replace('src.', 'src->')
-            safe_struct_body.append("\nvoid %s::initialize(const %s* src)\n{\n%s%s}" % (ss_name, ss_name, init_copy, init_construct))
+            safe_struct_body.append("\nvoid %s::initialize(const %s* src%s)\n{\n%s%s}" % (ss_name, ss_name, self.custom_construct_params.get(item.name, ''), init_copy, init_construct))
             if item.ifdef_protect != None:
                 safe_struct_body.append("#endif // %s\n" % item.ifdef_protect)
         return "\n".join(safe_struct_body)
index 23a54f6..d4bdbe0 100644 (file)
@@ -152,6 +152,8 @@ class ParameterValidationOutputGenerator(OutputGenerator):
             'vkCreateDebugReportCallbackEXT',
             'vkDestroyDebugReportCallbackEXT',
             'vkCreateCommandPool',
+            'vkCreateRenderPass',
+            'vkDestroyRenderPass',
             ]
         # Structure fields to ignore
         self.structMemberBlacklist = { 'VkWriteDescriptorSet' : ['dstSet'] }
index 9cfa954..c37bf0d 100644 (file)
@@ -150,6 +150,8 @@ class UniqueObjectsOutputGenerator(OutputGenerator):
             'vkGetPhysicalDeviceDisplayProperties2KHR',
             'vkGetPhysicalDeviceDisplayPlaneProperties2KHR',
             'vkGetDisplayModeProperties2KHR',
+            'vkCreateRenderPass',
+            'vkDestroyRenderPass',
             ]
         # Commands shadowed by interface functions and are not implemented
         self.interface_functions = [