2 subpass use same depth_stencil attachment as READ_ONLY

subpass “1” use color attachment A and subpass “2” use color attachment B, both use the same depth_stencil attachment as VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL.
The validation say:“A dependency between subpasses 1 and 2 must exist but one is not specified”, but Doc say:“If two subpasses use the same attachment in different layouts, and both layouts are read-only, no subpass dependency needs to be specified between those subpasses.”.

My problem is what mistake i made so i need provide a subpass-dependendcy.

I appreciate your time and help, i fought this problem almost 2 days, and hope someone could give me a help and thanks again.

Does the validation layer explain why it believes that a dependency “must exist”? We can’t see your code, so there may well be reasons other than your attachments.

Thanks for your help.

My RenderPass is:

. subpass0 (make z buffer):output color_attachment(nullptr)
depth_stencil(DEPTH_STENCIL_ATTACHMENT_OPTIMAL)+enable depthtest/write and disable stenciltest
. subpass1 (render opaque):output color_attachment(backbuffer)
depth_stencil(DEPTH_STENCIL_READ_ONLY_OPTIMAL)+enable depthtest and disable depth write/stenciltest
. subpass2 (render transparency):output color_attachment(TRANS_R8G8B8A8)
depth_stencil(DEPTH_STENCIL_READ_ONLY_OPTIMAL)+enable depthtest and disable depth write/stenciltest
. subpass3(final result):input(TRANS_R8G8B8A8)
output color_attachment(backbuffer)
depth_stencil(DEPTH_STENCIL_READ_ONLY_OPTIMAL)+enable depthtest and disable depth write/stenciltest

Dependency:
“”"""""""""""""""""""""""""""""----->subpass1
“”"""""""""""""""""""""""""""""/""""""""""""""""""\
EXTERNAL->subpass0 “”""""""""""""""""""—> subpass3
“”""""""""""""""""""""""""""""\""""""""""""""""""/
“”"""""""""""""""""""""""""""" ----->subpass2

The validation error come after call vkCmdBeginRenderPass and dosn’t say why.

The validation error will be gone If i removed the depth_stencil attachment from all of the 4 subpass or make a dependency between subpass1 and subpass2.

Thanks for your help again, If you need more infomation just let me know.

When I said “we can’t see your code,” what I meant was “you need to post your code”. Not an interpretation of your code; your actual code. If your code has bugs in it, your interpretation of it won’t have those bugs, so we’ll never know.

And when you do, please use proper formatting tags.

Alfonse_Reinheart thanks for your reminder and help.

I post my code on below and after call vkCmdBeginRenderPass the validation message is

A dependency between subpasses 1 and 2 must exist but one is not specified.
A dependency between subpasses 1 and 2 must exist but one is not specified.
A dependency between subpasses 2 and 1 must exist but one is not specified.
A dependency between subpasses 2 and 1 must exist but one is not specified.

    void example()
    {
    	VkExtent2D ext = knight::vulkan::env::GetSwapChainExtent();

    	VkImage			depthStencilImg;
    	VkDeviceMemory	depthStencilMem;
    	VkImageView		depthStencilImgView;
    	VkImageCreateInfo depthStencilCI = {
    		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, 0,
    		VK_IMAGE_TYPE_2D, VK_FORMAT_D24_UNORM_S8_UINT,
    		{ext.width, ext.height, 1},
    		1, 1, VK_SAMPLE_COUNT_1_BIT,
    		VK_IMAGE_TILING_OPTIMAL,
    		VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
    		VK_SHARING_MODE_EXCLUSIVE, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED
    	};
    	if (vkCreateImage(knight::vulkan::env::Device(), &depthStencilCI, nullptr, &depthStencilImg) == VK_SUCCESS)
    	{
    		VkMemoryRequirements memRequirements;
    		vkGetImageMemoryRequirements(knight::vulkan::env::Device(), depthStencilImg, &memRequirements);

    		VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    		allocInfo.allocationSize = memRequirements.size;
    		allocInfo.memoryTypeIndex = knight::vulkan::env::FindMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

    		if (vkAllocateMemory(knight::vulkan::env::Device(), &allocInfo, nullptr, &depthStencilMem) == VK_SUCCESS)
    		{
    			vkBindImageMemory(knight::vulkan::env::Device(), depthStencilImg, depthStencilMem, 0);

    			VkImageViewCreateInfo viewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
    			viewInfo.image = depthStencilImg;
    			viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
    			viewInfo.format = depthStencilCI.format;
    			viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
    			viewInfo.subresourceRange.baseMipLevel = 0;
    			viewInfo.subresourceRange.levelCount = 1;
    			viewInfo.subresourceRange.baseArrayLayer = 0;
    			viewInfo.subresourceRange.layerCount = 1;

    			if (vkCreateImageView(knight::vulkan::env::Device(), &viewInfo, nullptr, &depthStencilImgView) != VK_SUCCESS)
    			{
    				throw(-1);
    			}
    		}
    		else
    		{
    			throw(-1);
    		}
    	}

    	VkImage			transparencyImg;
    	VkDeviceMemory	transparencyMem;
    	VkImageView		transparencyImgView;
    	VkImageCreateInfo transparencyCI = {
    		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, 0,
    		VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, 
    		{ext.width, ext.height, 1},
    		1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL,
    		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
    		VK_SHARING_MODE_EXCLUSIVE, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED
    	};
    	if (vkCreateImage(knight::vulkan::env::Device(), &transparencyCI, nullptr, &transparencyImg) == VK_SUCCESS)
    	{
    		VkMemoryRequirements memRequirements;
    		vkGetImageMemoryRequirements(knight::vulkan::env::Device(), transparencyImg, &memRequirements);

    		VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    		allocInfo.allocationSize = memRequirements.size;
    		allocInfo.memoryTypeIndex = knight::vulkan::env::FindMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

    		if (vkAllocateMemory(knight::vulkan::env::Device(), &allocInfo, nullptr, &transparencyMem) == VK_SUCCESS)
    		{
    			vkBindImageMemory(knight::vulkan::env::Device(), transparencyImg, transparencyMem, 0);

    			VkImageViewCreateInfo viewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
    			viewInfo.image = transparencyImg;
    			viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
    			viewInfo.format = transparencyCI.format;
    			viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    			viewInfo.subresourceRange.baseMipLevel = 0;
    			viewInfo.subresourceRange.levelCount = 1;
    			viewInfo.subresourceRange.baseArrayLayer = 0;
    			viewInfo.subresourceRange.layerCount = 1;

    			if (vkCreateImageView(knight::vulkan::env::Device(), &viewInfo, nullptr, &transparencyImgView) != VK_SUCCESS)
    			{
    				throw(-1);
    			}
    		}
    		else
    		{
    			throw(-1);
    		}
    	}

    	enum {BACKBUFFER, DEPTH_STENCIL, TRANS_IMG};
    	std::vector<VkAttachmentDescription>	attachmentDescription(3);

    	attachmentDescription[BACKBUFFER] = { 
    		0, knight::vulkan::env::SwapChainFormat(), VK_SAMPLE_COUNT_1_BIT,
    		VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
    		VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
    		VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR };

    	attachmentDescription[DEPTH_STENCIL] = {
    		0, depthStencilCI.format, VK_SAMPLE_COUNT_1_BIT,
    		VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE,
    		VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE,
    		VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };

    	attachmentDescription[TRANS_IMG] = {
    		0, transparencyCI.format, VK_SAMPLE_COUNT_1_BIT,
    		VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE,
    		VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
    		VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };

    	std::vector<VkImageView> attachmentImageView;

    	attachmentImageView.push_back(knight::vulkan::env::GetSwapChainImageViews()[0]);
    	attachmentImageView.push_back(depthStencilImgView);
    	attachmentImageView.push_back(transparencyImgView);

    	std::vector<VkSubpassDescription> subpassDescription;
    	subpassDescription.push_back({
    		0, VK_PIPELINE_BIND_POINT_GRAPHICS,
    		0, nullptr,
    		0, nullptr,
    		nullptr,
    		new VkAttachmentReference{DEPTH_STENCIL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL},
    		0, nullptr
    		});
    	subpassDescription.push_back({
    		0, VK_PIPELINE_BIND_POINT_GRAPHICS,
    		0, nullptr,
    		1, new VkAttachmentReference{BACKBUFFER, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
    		nullptr,
    		new VkAttachmentReference{DEPTH_STENCIL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL},
    		0, nullptr
    		});
    	subpassDescription.push_back({
    		0, VK_PIPELINE_BIND_POINT_GRAPHICS,
    		0, nullptr,
    		1, new VkAttachmentReference{TRANS_IMG, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
    		nullptr,
    		new VkAttachmentReference{DEPTH_STENCIL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL},
    		0, nullptr
    		});
    	subpassDescription.push_back({
    		0, VK_PIPELINE_BIND_POINT_GRAPHICS,
    		1, new VkAttachmentReference{TRANS_IMG, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
    		1, new VkAttachmentReference{BACKBUFFER, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
    		nullptr,
    		new VkAttachmentReference{DEPTH_STENCIL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL},
    		0, nullptr
    		});

    	std::vector<VkSubpassDependency> subpassDependency;
    	subpassDependency.push_back({
    		VK_SUBPASS_EXTERNAL, 0,
    		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
    		0,												VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
    		});
    	subpassDependency.push_back({
    		0, 1,
    		VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,	VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
    		VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
    		});
    	subpassDependency.push_back({
    		0, 2,
    		VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,	VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
    		VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
    		});
    	subpassDependency.push_back({
    		1, 3,
    		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
    		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT
    		});
    	subpassDependency.push_back({
    		2, 3,
    		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
    		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT
    		});


    	VkRenderPass renderPass;
    	VkFramebuffer frameBuffer;
    	VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
    	renderPassInfo.attachmentCount = uint32_t(attachmentDescription.size());
    	renderPassInfo.pAttachments = attachmentDescription.data();
    	renderPassInfo.subpassCount = uint32_t(subpassDescription.size());
    	renderPassInfo.pSubpasses = subpassDescription.data();
    	renderPassInfo.dependencyCount = uint32_t(subpassDependency.size());
    	renderPassInfo.pDependencies = subpassDependency.data();
    	if (vkCreateRenderPass(knight::vulkan::env::Device(), &renderPassInfo, nullptr, &renderPass) == VK_SUCCESS)
    	{
    		//for (auto &imgViews : m_SwapImageViews)
    		{
    			VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
    			framebufferInfo.renderPass = renderPass;
    			framebufferInfo.attachmentCount = uint32_t(attachmentImageView.size());
    			framebufferInfo.pAttachments = attachmentImageView.data();
    			framebufferInfo.width = ext.width;
    			framebufferInfo.height = ext.height;
    			framebufferInfo.layers = 1;
    			
    			if (vkCreateFramebuffer(knight::vulkan::env::Device(), &framebufferInfo, nullptr, &frameBuffer) != VK_SUCCESS)
    			{
    				throw(-1);
    			}
    		}
    	}
    	else
    	{
    		throw(-1);
    	}

    	std::vector<VkCommandBuffer> primaryCommandBuffer(3);
    	VkCommandBufferAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
    	allocInfo.commandPool = knight::vulkan::env::CommandPool(knight::vulkan::env::RENDER_POOL);
    	allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    	allocInfo.commandBufferCount = (uint32_t)primaryCommandBuffer.size();
    	if (vkAllocateCommandBuffers(knight::vulkan::env::Device(), &allocInfo, primaryCommandBuffer.data()) != VK_SUCCESS) {
    		throw(-1);
    	}

    	VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
    	vkBeginCommandBuffer(primaryCommandBuffer[0], &beginInfo);

    	std::vector<VkClearValue> clearValue = {
    		{0.0f,0.0f,0.0f,0.0f},
    		{1.0f, 0},
    		{0.0f,0.0f,0.0f,0.0f}
    	};
    	VkRenderPassBeginInfo renderPassBeginInfo = {};
    	renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    	renderPassBeginInfo.renderPass = renderPass;
    	renderPassBeginInfo.renderArea.offset = {0,0};
    	renderPassBeginInfo.renderArea.extent = ext;
    	renderPassBeginInfo.clearValueCount = uint32_t(clearValue.size());
    	renderPassBeginInfo.pClearValues = clearValue.data();
    	renderPassBeginInfo.framebuffer = frameBuffer;

    	vkCmdBeginRenderPass(primaryCommandBuffer[0], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);

    }

Do you need more source code or the formatting tags what i used is not correct?

If you need anything just let me know, appreciate your help thank you.

I can reproduce. Possibly layer bug.

Thank you for your attention, Have you verify the “Layer bug” is the only problem?

No, but I used none of your code. Therefore being able to reproduce it independently, I find it probable it is layer bug.

There’s possibly also some spec bug component to this. Technically the spec says “in different layouts”, and you use them in the same layout. Though it seems logical to me that Vulkan should cover that case also if it can handle the harder case of different layouts. So I think this is as good as spec bug.

You would be kind to report this to respective repos: KhronosGroup/Vulkan-ValidationLayers and KhronosGroup/Vulkan-Docs

krOoze thanks for your help.I had make a issue on KhronosGroup/Vulkan-ValidationLayers.