I need render to textrue in my project.
Pass1 : Draw a color square that color is (0.5,0.5,0.5,1.0) and render target is a texture.
Pass2 : Draw a textured square that use pass1's texture and render target is a surface.
Expected result:

But I got strange result as follow:

Create image using the following:
VkImage hImageTexture = VK_NULL_HANDLE;
VkImageCreateInfo imageCreateInfo = {0};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.pNext = nullptr;
imageCreateInfo.flags = 0;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.queueFamilyIndexCount = 0;
imageCreateInfo.pQueueFamilyIndices = nullptr;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
//
VkResult res = vkCreateImage(hDevice , &imageCreateInfo , nullptr , &hImageTexture);
Create image view using the following:
VkImageView hImageViewTexture = VK_NULL_HANDLE;
VkImageViewCreateInfo imageViewCreateInfo = {0};
imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCreateInfo.pNext = nullptr;
imageViewCreateInfo.flags = 0;
imageViewCreateInfo.image = hImageTexture;
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A;
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
imageViewCreateInfo.subresourceRange.levelCount = 1;
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
imageViewCreateInfo.subresourceRange.layerCount = 1;
VkResult res=vkCreateImageView(
hDevice,
&imageViewCreateInfo,
NULL,
&hImageViewTexture);
Render loop as follows:
//Pass1
//Clear texture color
vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
vkCmdClearColorImage();//Clear color(0.0 , 0.0 ,0.0 , 1.0)
vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
//Change texture's barrier
VkImageMemoryBarrier imageMemoryBarrierForOutput = {0};
imageMemoryBarrierForOutput.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrierForOutput.pNext = nullptr;
imageMemoryBarrierForOutput.srcAccessMask = 0;
imageMemoryBarrierForOutput.dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrierForOutput.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrierForOutput.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrierForOutput.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrierForOutput.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrierForOutput.image = hImageTexture;
imageMemoryBarrierForOutput.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrierForOutput.subresourceRange.baseMipLevel = 0;
imageMemoryBarrierForOutput.subresourceRange.levelCount = 1;
imageMemoryBarrierForOutput.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrierForOutput.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
hCommandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&imageMemoryBarrierForOutput);
//draw
vkCmdBeginRenderPass();
vkCmdSetViewport();
vkCmdSetScissor();
vkCmdBindPipeline();
vkCmdBindDescriptorSets();
vkCmdBindVertexBuffers();
vkCmdBindIndexBuffer();
vkCmdDrawIndexed();
vkCmdEndRenderPass();
//
//Pass2
//Clear surface color
vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
vkCmdClearColorImage();//Clear color(0.5 , 0.5 ,1.0 , 1.0)
vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
//Change texture's barrier
VkImageMemoryBarrier imageMemoryBarrierForInput = {0};
imageMemoryBarrierForInput.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrierForInput.pNext = nullptr;
imageMemoryBarrierForInput.srcAccessMask = 0;
imageMemoryBarrierForInput.dstAccessMask =
VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
imageMemoryBarrierForInput.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrierForInput.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageMemoryBarrierForInput.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrierForInput.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrierForInput.image = hImageTexture;
imageMemoryBarrierForInput.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrierForInput.subresourceRange.baseMipLevel = 0;
imageMemoryBarrierForInput.subresourceRange.levelCount = 1;
imageMemoryBarrierForInput.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrierForInput.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
hCommandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&imageMemoryBarrierForInput);
//draw
vkCmdBeginRenderPass();
vkCmdSetViewport();
vkCmdSetScissor();
vkCmdBindPipeline();
vkCmdBindDescriptorSets();
vkCmdBindVertexBuffers();
vkCmdBindIndexBuffer();
vkCmdDrawIndexed();
vkCmdEndRenderPass();
Pass1 vertex shader:
#version 450
layout (location=0) in vec4 inPos;
layout (location=0) out vec4 outPos;
void main(void)
{
outPos = float4(inPos.xy , 0.0 , 1.0);
gl_Position = outPos;
}
Pass1 fragment shader:
#version 450
layout (location=0) in vec4 inPos;
layout (location=0) out vec4 outColor;
void main(void)
{
outColor = float4(0.5 , 0.5 , 0.5 , 1.0);
}
Pass2 vertex shader:
#version 450
layout (location=0) in vec4 inPos;
layout (location=1) in vec2 inUV;
//
layout (location=0) out vec4 outPos;
layout (location=1) out vec2 outUV;
//
void main(void)
{
outPos = inPos;
outUV = inUV;
//
gl_Position=outPos;
}
Pass2 fragment shader:
#version 450
//
layout (location=0) in vec4 inPos;
layout (location=1) in vec2 inUV;
//
layout (binding=1) uniform sampler2D inTex;
layout (location=0) out vec4 outColor;
void main(void)
{
outColor = texture(inTex , inUV);
}
If I change image tiling to VK_IMAGE_TILING_LINEAR then I get the following:

If change image tiling to VK_IMAGE_TILING_LINEAR without clear(pass1's clear), the result was correct!
What mistakes have I made?
EDIT: I add some code that how i change texture's barrier in render loop .
EDIT: I set dependency when create render pass as follow
VkSubpassDependency subpassDependency[2];
subpassDependency[0].srcSubpass = VK_SUBPASS_EXTERNAL;
subpassDependency[0].dstSubpass = 0;
subpassDependency[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
subpassDependency[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependency[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
subpassDependency[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpassDependency[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
//
subpassDependency[1].srcSubpass = 0;
subpassDependency[1].dstSubpass = VK_SUBPASS_EXTERNAL;
subpassDependency[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependency[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
subpassDependency[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpassDependency[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
subpassDependency[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
but nothing to changed.
What you have here is a graphics-graphics dependency on the first pass output color attachment.
The second subpass shader read operations have to wait for the first subpass color attachment writing operations to be done.
VkSubpassDependency deps[...];
//other values to handle external dependencies
...
// the src operations will refer to the first subpass
deps[0].srcSubpass = 0;
// the dst operations will refer to the second subpass
deps[0].dstSubpass = 1;
// the operations from the first subpass that will have to be completed
// the writes to the color attachment in the color attachment output stage
deps[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
deps[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
// this operations will wait on those specified in the previous lines
// the reads issued during the fragment shader will have to wait
// until all the writes have been completed
deps[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
deps[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
// do not wait for every write to have finished
// if all writes in a region have been completed
// then the reads can start (only in that region)
deps[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
This takes care of the synchronization between the subpasses and the changes of layout in one frame as the subpasses specify the layouts of the attachments.
Then you need to signal to the pipeline that you intend to move to the next render pass.
//draw
vkCmdBeginRenderPass();
vkCmdSetViewport();
vkCmdSetScissor();
vkCmdBindPipeline();
vkCmdBindDescriptorSets();
vkCmdBindVertexBuffers();
vkCmdBindIndexBuffer();
vkCmdDrawIndexed();
vkNextSubpass();
vkCmdSetViewport();
vkCmdSetScissor();
vkCmdBindPipeline();
vkCmdBindDescriptorSets();
vkCmdBindVertexBuffers();
vkCmdBindIndexBuffer();
vkCmdDrawIndexed();
vkCmdEndRenderPass();
For examples of common synchronization operations you can check out the vulkan synchronization examples page.
Your problem is First draw writes to a color attachment. Second draw reads from it as an input attachment in the fragment shader as you are doing everything in one render pass by dividing it in more subpasses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With