layers: GH690 Save renderPass create info in PSO
authorTobin Ehlis <tobine@google.com>
Mon, 27 Jun 2016 18:57:05 +0000 (12:57 -0600)
committerTobin Ehlis <tobine@google.com>
Wed, 6 Jul 2016 14:05:37 +0000 (08:05 -0600)
The renderPass that a pipeline is created with may be destroyed before
the pipeline is used in a draw. In order to make sure that the renderPass
data will live as long as the pipeline, save the VkRenderPassCreateInfo
using a safe_VkRenderPassCreateInfo in the PIPELINE_NODE struct.

layers/core_validation.cpp
layers/core_validation.h

index 4c400b4..01efd53 100644 (file)
@@ -1776,12 +1776,14 @@ static bool validate_vi_against_vs_inputs(debug_report_data *report_data, VkPipe
 }
 
 static bool validate_fs_outputs_against_render_pass(debug_report_data *report_data, shader_module const *fs,
-                                                    spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) {
+                                                    spirv_inst_iter entrypoint, VkRenderPassCreateInfo const *rpci,
+                                                    uint32_t subpass_index) {
     std::map<location_t, interface_var> outputs;
     std::map<uint32_t, VkFormat> color_attachments;
-    for (auto i = 0u; i < rp->subpassColorFormats[subpass].size(); i++) {
-        if (rp->subpassColorFormats[subpass][i] != VK_FORMAT_UNDEFINED) {
-            color_attachments[i] = rp->subpassColorFormats[subpass][i];
+    auto subpass = rpci->pSubpasses[subpass_index];
+    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
+        if (rpci->pAttachments[subpass.pColorAttachments[i].attachment].format != VK_FORMAT_UNDEFINED) {
+            color_attachments[i] = rpci->pAttachments[subpass.pColorAttachments[i].attachment].format;
         }
     }
 
@@ -2202,11 +2204,10 @@ static bool attachment_references_compatible(const uint32_t index, const VkAttac
     return false;
 }
 
-// For given primary and secondary RenderPass objects, verify that they're compatible
-static bool verify_renderpass_compatibility(const layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP,
-                                            string &errorMsg) {
+// For given primary RenderPass object and secondry RenderPassCreateInfo, verify that they're compatible
+static bool verify_renderpass_compatibility(const layer_data *my_data, const VkRenderPass primaryRP,
+                                            const VkRenderPassCreateInfo *secondaryRPCI, string &errorMsg) {
     auto primary_render_pass = getRenderPass(my_data, primaryRP);
-    auto secondary_render_pass = getRenderPass(my_data, secondaryRP);
 
     if (!primary_render_pass) {
         stringstream errorStr;
@@ -2215,18 +2216,7 @@ static bool verify_renderpass_compatibility(const layer_data *my_data, const VkR
         return false;
     }
 
-    if (!secondary_render_pass) {
-        stringstream errorStr;
-        errorStr << "invalid VkRenderPass (" << secondaryRP << ")";
-        errorMsg = errorStr.str();
-        return false;
-    }
-    // Trivial pass case is exact same RP
-    if (primaryRP == secondaryRP) {
-        return true;
-    }
     const VkRenderPassCreateInfo *primaryRPCI = primary_render_pass->pCreateInfo;
-    const VkRenderPassCreateInfo *secondaryRPCI = secondary_render_pass->pCreateInfo;
     if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
         stringstream errorStr;
         errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
@@ -2286,6 +2276,25 @@ static bool verify_renderpass_compatibility(const layer_data *my_data, const VkR
     return true;
 }
 
+// For given primary and secondary RenderPass objects, verify that they're compatible
+static bool verify_renderpass_compatibility(const layer_data *dev_data, const VkRenderPass primaryRP,
+                                            const VkRenderPass secondaryRP, string &errorMsg) {
+    // Handle trivial match case first
+    if (primaryRP == secondaryRP)
+        return true;
+
+    auto secondary_render_pass = getRenderPass(dev_data, secondaryRP);
+
+    if (!secondary_render_pass) {
+        stringstream errorStr;
+        errorStr << "invalid VkRenderPass (" << secondaryRP << ")";
+        errorMsg = errorStr.str();
+        return false;
+    }
+    const VkRenderPassCreateInfo *secondaryRPCI = secondary_render_pass->pCreateInfo;
+    return verify_renderpass_compatibility(dev_data, primaryRP, secondaryRPCI, errorMsg);
+}
+
 // For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
 // pipelineLayout[layoutIndex]
 static bool verify_set_layout_compatibility(layer_data *my_data, const cvdescriptorset::DescriptorSet *pSet,
@@ -2717,9 +2726,9 @@ static bool validate_and_capture_pipeline_shader_state(debug_report_data *report
         }
     }
 
-    if (shaders[fragment_stage] && pPipeline->renderPass) {
+    if (shaders[fragment_stage]) {
         pass &= validate_fs_outputs_against_render_pass(report_data, shaders[fragment_stage], entrypoints[fragment_stage],
-                                                        pPipeline->renderPass, pCreateInfo->subpass);
+                                                        pPipeline->render_pass_ci.ptr(), pCreateInfo->subpass);
     }
 
     return pass;
@@ -2892,7 +2901,7 @@ static bool validatePipelineDrawtimeState(layer_data const *my_data,
     // Verify that PSO creation renderPass is compatible with active renderPass
     if (pCB->activeRenderPass) {
         std::string err_string;
-        if (!verify_renderpass_compatibility(my_data, pCB->activeRenderPass->renderPass, pPipeline->graphicsPipelineCI.renderPass,
+        if (!verify_renderpass_compatibility(my_data, pCB->activeRenderPass->renderPass, pPipeline->render_pass_ci.ptr(),
                                              err_string)) {
             // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
             skip_call |=
@@ -5851,7 +5860,7 @@ CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t
     for (i = 0; i < count; i++) {
         pPipeNode[i] = new PIPELINE_NODE;
         pPipeNode[i]->initGraphicsPipeline(&pCreateInfos[i]);
-        pPipeNode[i]->renderPass = getRenderPass(dev_data, pCreateInfos[i].renderPass);
+        pPipeNode[i]->render_pass_ci.initialize(getRenderPass(dev_data, pCreateInfos[i].renderPass)->pCreateInfo);
         pPipeNode[i]->pipelineLayout = getPipelineLayout(dev_data, pCreateInfos[i].layout);
 
         skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i);
index a205ea6..320833f 100644 (file)
@@ -147,13 +147,15 @@ class PIPELINE_NODE {
     std::vector<VkVertexInputAttributeDescription> vertexAttributeDescriptions;
     std::vector<VkPipelineColorBlendAttachmentState> attachments;
     bool blendConstantsEnabled; // Blend constants enabled for any attachments
-    RENDER_PASS_NODE *renderPass;
+    // Store RPCI b/c renderPass may be destroyed after Pipeline creation
+    safe_VkRenderPassCreateInfo render_pass_ci;
     PIPELINE_LAYOUT_NODE const *pipelineLayout;
 
     // Default constructor
     PIPELINE_NODE()
-        : pipeline{}, graphicsPipelineCI{}, computePipelineCI{}, active_shaders(0), duplicate_shaders(0), active_slots(), vertexBindingDescriptions(),
-          vertexAttributeDescriptions(), attachments(), blendConstantsEnabled(false), renderPass(nullptr), pipelineLayout(nullptr) {}
+        : pipeline{}, graphicsPipelineCI{}, computePipelineCI{}, active_shaders(0), duplicate_shaders(0), active_slots(),
+          vertexBindingDescriptions(), vertexAttributeDescriptions(), attachments(), blendConstantsEnabled(false), render_pass_ci(),
+          pipelineLayout(nullptr) {}
 
     void initGraphicsPipeline(const VkGraphicsPipelineCreateInfo *pCreateInfo) {
         graphicsPipelineCI.initialize(pCreateInfo);