Fix image memory barriers
Use proper stages and access masks This fixes image memory barrier validation Refs #631
This commit is contained in:
parent
39852c4a27
commit
7086684979
2 changed files with 72 additions and 64 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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,
|
// Binding 1: Sampled image
|
||||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, &textureDescriptor)
|
||||||
0,
|
};
|
||||||
&uniformBufferVS.descriptor));
|
|
||||||
|
|
||||||
// Binding 1: Sampled image
|
|
||||||
VkDescriptorImageInfo 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue