tests: Add InvalidCmdBufferPipelineDestroyed test
Bind a pipeline to a cmd buffer and then destroy pipeline and attempt to submit
cmd buffer, verifying that it's flagged as invalid.
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index deb93cf..225be9a 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -6606,6 +6606,114 @@
m_errorMonitor->VerifyFound();
}
+TEST_F(VkLayerTest, InvalidCmdBufferPipelineDestroyed) {
+ TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid "
+ "due to a pipeline dependency being destroyed.");
+ ASSERT_NO_FATAL_FAILURE(InitState());
+ ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+
+ VkResult err;
+
+ VkPipelineLayoutCreateInfo pipeline_layout_ci = {};
+ pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+
+ VkPipelineLayout pipeline_layout;
+ err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL,
+ &pipeline_layout);
+ ASSERT_VK_SUCCESS(err);
+
+ VkPipelineViewportStateCreateInfo vp_state_ci = {};
+ vp_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vp_state_ci.viewportCount = 1;
+ VkViewport vp = {}; // Just need dummy vp to point to
+ vp_state_ci.pViewports = &vp; // Null vp w/ count of 1 should cause error
+ vp_state_ci.scissorCount = 1;
+ VkRect2D scissors = {}; // Dummy scissors to point to
+ vp_state_ci.pScissors = &scissors;
+ // No dynamic state
+ VkPipelineDynamicStateCreateInfo dyn_state_ci = {};
+ dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+
+ VkPipelineShaderStageCreateInfo shaderStages[2];
+ memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
+
+ VkShaderObj vs(m_device, bindStateVertShaderText,
+ VK_SHADER_STAGE_VERTEX_BIT, this);
+ VkShaderObj fs(m_device, bindStateFragShaderText,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ this); // We shouldn't need a fragment shader
+ // but add it to be able to run on more devices
+ shaderStages[0] = vs.GetStageCreateInfo();
+ shaderStages[1] = fs.GetStageCreateInfo();
+
+ VkPipelineVertexInputStateCreateInfo vi_ci = {};
+ vi_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+
+ VkPipelineInputAssemblyStateCreateInfo ia_ci = {};
+ ia_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ia_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+
+ VkPipelineRasterizationStateCreateInfo rs_ci = {};
+ rs_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+
+ VkPipelineColorBlendAttachmentState att = {};
+ att.blendEnable = VK_FALSE;
+ att.colorWriteMask = 0xf;
+
+ VkPipelineColorBlendStateCreateInfo cb_ci = {};
+ cb_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cb_ci.attachmentCount = 1;
+ cb_ci.pAttachments = &att;
+
+ VkGraphicsPipelineCreateInfo gp_ci = {};
+ gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ gp_ci.stageCount = 2;
+ gp_ci.pStages = shaderStages;
+ gp_ci.pVertexInputState = &vi_ci;
+ gp_ci.pInputAssemblyState = &ia_ci;
+ gp_ci.pViewportState = &vp_state_ci;
+ gp_ci.pRasterizationState = &rs_ci;
+ gp_ci.pColorBlendState = &cb_ci;
+ gp_ci.pDynamicState = &dyn_state_ci;
+ gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT;
+ gp_ci.layout = pipeline_layout;
+ gp_ci.renderPass = renderPass();
+
+ VkPipelineCacheCreateInfo pc_ci = {};
+ pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+
+ VkPipeline pipeline;
+ VkPipelineCache pipelineCache;
+ err =
+ vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache);
+ ASSERT_VK_SUCCESS(err);
+
+ err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1,
+ &gp_ci, NULL, &pipeline);
+ ASSERT_VK_SUCCESS(err);
+
+ m_commandBuffer->BeginCommandBuffer();
+ vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(),
+ VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ m_commandBuffer->EndCommandBuffer();
+ // Now destroy pipeline in order to cause error when submitting
+ vkDestroyPipeline(m_device->device(), pipeline, nullptr);
+
+ m_errorMonitor->SetDesiredFailureMsg(
+ VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " that is invalid because bound pipeline ");
+
+ VkSubmitInfo submit_info = {};
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &m_commandBuffer->handle();
+ vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
+
+ m_errorMonitor->VerifyFound();
+ vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL);
+ vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL);
+}
+
TEST_F(VkLayerTest, InvalidPipeline) {
// Attempt to bind an invalid Pipeline to a valid Command Buffer
// ObjectTracker should catch this.