Fix image memory barriers

Use proper stages and access masks
This fixes image memory barrier validation
Refs #631
This commit is contained in:
Sascha Willems 2019-11-19 19:07:03 +01:00
parent 39852c4a27
commit 7086684979
2 changed files with 72 additions and 64 deletions

View file

@ -68,15 +68,16 @@ subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.levelCount = 1; subresourceRange.levelCount = 1;
subresourceRange.layerCount = 1; subresourceRange.layerCount = 1;
vkTools::setImageLayout( vks::tools::insertImageMemoryBarrier(
copyCmd, copyCmd,
texture.image, texture.image,
VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
subresourceRange,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT); VK_PIPELINE_STAGE_TRANSFER_BIT,
subresourceRange);
``` ```
### Generating the mip-chain ### Generating the mip-chain
@ -119,16 +120,17 @@ Before we can blit to this mip level, we need to transition it's image layout to
mipSubRange.levelCount = 1; mipSubRange.levelCount = 1;
mipSubRange.layerCount = 1; mipSubRange.layerCount = 1;
// Transiton current mip level to transfer dest // Prepare current mip level as image blit destination
vkTools::setImageLayout( vks::tools::insertImageMemoryBarrier(
blitCmd, blitCmd,
texture.image, texture.image,
VK_IMAGE_ASPECT_COLOR_BIT, 0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
mipSubRange,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT); VK_PIPELINE_STAGE_TRANSFER_BIT,
mipSubRange);
``` ```
Note that we set the ```baseMipLevel``` member of the subresource range so the image memory barrier will only affect the one mip level we want to copy to. Note that we set the ```baseMipLevel``` member of the subresource range so the image memory barrier will only affect the one mip level we want to copy to.
@ -150,15 +152,17 @@ Now that the mip level we want to copy from and the one we'll copy to have are i
After the blit is done we can use this mip level as a base for the next level, so we transition the layout from ```TRANSFER_DST_OPTIMAL``` to ```TRANSFER_SRC_OPTIMAL``` so we can use this level as transfer source for the next level: After the blit is done we can use this mip level as a base for the next level, so we transition the layout from ```TRANSFER_DST_OPTIMAL``` to ```TRANSFER_SRC_OPTIMAL``` so we can use this level as transfer source for the next level:
```cpp ```cpp
vkTools::setImageLayout( // Prepare current mip level as image blit source for next level
blitCmd, vks::tools::insertImageMemoryBarrier(
copyCmd,
texture.image, texture.image,
VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
mipSubRange,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT); VK_PIPELINE_STAGE_TRANSFER_BIT,
mipSubRange);
} }
``` ```
@ -167,15 +171,16 @@ Once the loop is done we need to transition all mip levels of the image to their
```cpp ```cpp
subresourceRange.levelCount = texture.mipLevels; subresourceRange.levelCount = texture.mipLevels;
vkTools::setImageLayout( vks::tools::insertImageMemoryBarrier(
blitCmd, copyCmd,
texture.image, texture.image,
VK_IMAGE_ASPECT_COLOR_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
subresourceRange,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT); VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
subresourceRange);
``` ```
Submitting that command buffer will result in an image with a complete mip-chain and all mip levels being transitioned to the proper image layout for shader reads. Submitting that command buffer will result in an image with a complete mip-chain and all mip levels being transitioned to the proper image layout for shader reads.

View file

@ -1,7 +1,7 @@
/* /*
* Vulkan Example - Runtime mip map generation * Vulkan Example - Runtime mip map generation
* *
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de * Copyright (C) by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
@ -35,7 +35,6 @@ class VulkanExample : public VulkanExampleBase
public: public:
struct Texture { struct Texture {
VkImage image; VkImage image;
VkImageLayout imageLayout;
VkDeviceMemory deviceMemory; VkDeviceMemory deviceMemory;
VkImageView view; VkImageView view;
uint32_t width, height; uint32_t width, height;
@ -110,6 +109,13 @@ public:
models.tunnel.destroy(); models.tunnel.destroy();
} }
virtual void getEnabledFeatures()
{
if (deviceFeatures.samplerAnisotropy) {
enabledFeatures.samplerAnisotropy = VK_TRUE;
}
}
void loadTexture(std::string fileName, VkFormat format, bool forceLinearTiling) void loadTexture(std::string fileName, VkFormat format, bool forceLinearTiling)
{ {
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -200,11 +206,15 @@ public:
subresourceRange.layerCount = 1; subresourceRange.layerCount = 1;
// Optimal image will be used as destination for the copy, so we must transfer from our initial undefined image layout to the transfer destination layout // Optimal image will be used as destination for the copy, so we must transfer from our initial undefined image layout to the transfer destination layout
vks::tools::setImageLayout( vks::tools::insertImageMemoryBarrier(
copyCmd, copyCmd,
texture.image, texture.image,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
subresourceRange); subresourceRange);
// Copy the first mip of the chain, remaining mips will be generated // Copy the first mip of the chain, remaining mips will be generated
@ -220,12 +230,15 @@ public:
vkCmdCopyBufferToImage(copyCmd, stagingBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); vkCmdCopyBufferToImage(copyCmd, stagingBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion);
// Transition first mip level to transfer source for read during blit // Transition first mip level to transfer source for read during blit
texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vks::tools::insertImageMemoryBarrier(
vks::tools::setImageLayout(
copyCmd, copyCmd,
texture.image, texture.image,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
subresourceRange); subresourceRange);
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
@ -267,15 +280,17 @@ public:
mipSubRange.levelCount = 1; mipSubRange.levelCount = 1;
mipSubRange.layerCount = 1; mipSubRange.layerCount = 1;
// Transiton current mip level to transfer dest // Prepare current mip level as image blit destination
vks::tools::setImageLayout( vks::tools::insertImageMemoryBarrier(
blitCmd, blitCmd,
texture.image, texture.image,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
mipSubRange,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT); VK_PIPELINE_STAGE_TRANSFER_BIT,
mipSubRange);
// Blit from previous level // Blit from previous level
vkCmdBlitImage( vkCmdBlitImage(
@ -288,24 +303,30 @@ public:
&imageBlit, &imageBlit,
VK_FILTER_LINEAR); VK_FILTER_LINEAR);
// Transiton current mip level to transfer source for read in next iteration // Prepare current mip level as image blit source for next level
vks::tools::setImageLayout( vks::tools::insertImageMemoryBarrier(
blitCmd, copyCmd,
texture.image, texture.image,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
mipSubRange, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT); mipSubRange);
} }
// After the loop, all mip layers are in TRANSFER_SRC layout, so transition all to SHADER_READ // After the loop, all mip layers are in TRANSFER_SRC layout, so transition all to SHADER_READ
subresourceRange.levelCount = texture.mipLevels; subresourceRange.levelCount = texture.mipLevels;
vks::tools::setImageLayout( vks::tools::insertImageMemoryBarrier(
blitCmd, copyCmd,
texture.image, texture.image,
VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
texture.imageLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
subresourceRange); subresourceRange);
VulkanExampleBase::flushCommandBuffer(blitCmd, queue, true); VulkanExampleBase::flushCommandBuffer(blitCmd, queue, true);
@ -534,34 +555,17 @@ public:
void setupDescriptorSet() void setupDescriptorSet()
{ {
VkDescriptorSetAllocateInfo allocInfo = VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout,1);
vks::initializers::descriptorSetAllocateInfo(
descriptorPool,
&descriptorSetLayout,
1);
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
std::vector<VkWriteDescriptorSet> writeDescriptorSets; VkDescriptorImageInfo textureDescriptor = vks::initializers::descriptorImageInfo(VK_NULL_HANDLE, texture.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
// Binding 0: Vertex shader uniform buffer // Binding 0: Vertex shader uniform buffer
writeDescriptorSets.push_back(vks::initializers::writeDescriptorSet( vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBufferVS.descriptor),
descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&uniformBufferVS.descriptor));
// Binding 1: Sampled image // Binding 1: Sampled image
VkDescriptorImageInfo textureDescriptor = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, &textureDescriptor)
vks::initializers::descriptorImageInfo( };
VK_NULL_HANDLE,
texture.view,
texture.imageLayout);
writeDescriptorSets.push_back(vks::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
1,
&textureDescriptor));
// Binding 2: Sampler array // Binding 2: Sampler array
std::vector<VkDescriptorImageInfo> samplerDescriptors; std::vector<VkDescriptorImageInfo> samplerDescriptors;
@ -578,7 +582,6 @@ public:
samplerDescriptorWrite.dstBinding = 2; samplerDescriptorWrite.dstBinding = 2;
samplerDescriptorWrite.dstArrayElement = 0; samplerDescriptorWrite.dstArrayElement = 0;
writeDescriptorSets.push_back(samplerDescriptorWrite); writeDescriptorSets.push_back(samplerDescriptorWrite);
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
} }