I'm trying to use the synchronization validation of VK_LAYER_KHRONOS_validation
in my vulkan application, but appear to be unable to "make it happy".
In the debugging process I've reduced the problem down to the a vkCmdDispatch -> full pipeline barrier -> vkCmdCopyBuffer which (according to my understanding) should not result in a RaW-hazard.
An excerpt of the relevant part of the API dump is show below:
Thread 0, Frame 0:
vkCmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline) returns void:
commandBuffer: VkCommandBuffer = 0x5651fe89b9f0
pipelineBindPoint: VkPipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE (1)
pipeline: VkPipeline = 0x5651fff4e5e0
Thread 0, Frame 0:
vkCmdPushDescriptorSetKHR(commandBuffer, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites) returns void:
commandBuffer: VkCommandBuffer = 0x5651fe89b9f0
pipelineBindPoint: VkPipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE (1)
layout: VkPipelineLayout = 0x5651fff4e270
set: uint32_t = 0
descriptorWriteCount: uint32_t = 1
pDescriptorWrites: const VkWriteDescriptorSet* = 0x7ffe711a6130
pDescriptorWrites[0]: const VkWriteDescriptorSet = 0x7ffe711a6130:
sType: VkStructureType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET (35)
pNext: const void* = NULL
dstSet: VkDescriptorSet = 0
dstBinding: uint32_t = 0
dstArrayElement: uint32_t = 0
descriptorCount: uint32_t = 1
descriptorType: VkDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER (7)
pImageInfo: const VkDescriptorImageInfo* = UNUSED
pBufferInfo: const VkDescriptorBufferInfo* = 0x5651fea830b0
pBufferInfo[0]: const VkDescriptorBufferInfo = 0x5651fea830b0:
buffer: VkBuffer = 0x5651ffcbf560
offset: VkDeviceSize = 0
range: VkDeviceSize = 1048576
pTexelBufferView: const VkBufferView* = UNUSED
Thread 0, Frame 0:
vkCmdDispatch(commandBuffer, groupCountX, groupCountY, groupCountZ) returns void:
commandBuffer: VkCommandBuffer = 0x5651fe89b9f0
groupCountX: uint32_t = 1024
groupCountY: uint32_t = 1
groupCountZ: uint32_t = 1
Thread 0, Frame 0:
vkCmdPipelineBarrier2(commandBuffer, pDependencyInfo) returns void:
commandBuffer: VkCommandBuffer = 0x5651fe89b9f0
pDependencyInfo: const VkDependencyInfo* = 0x7ffe711a6280:
sType: VkStructureType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO (1000314003)
pNext: const void* = NULL
dependencyFlags: VkDependencyFlags = 0
memoryBarrierCount: uint32_t = 1
pMemoryBarriers: const VkMemoryBarrier2* = 0x7ffe711a6130
pMemoryBarriers[0]: const VkMemoryBarrier2 = 0x7ffe711a6130:
sType: VkStructureType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 (1000314000)
pNext: const void* = NULL
srcStageMask: VkPipelineStageFlags2 = 65536 (VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
srcAccessMask: VkAccessFlags2 = 98304 (VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT)
dstStageMask: VkPipelineStageFlags2 = 65536 (VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
dstAccessMask: VkAccessFlags2 = 98304 (VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT)
bufferMemoryBarrierCount: uint32_t = 0
pBufferMemoryBarriers: const VkBufferMemoryBarrier2* = NULL
imageMemoryBarrierCount: uint32_t = 0
pImageMemoryBarriers: const VkImageMemoryBarrier2* = NULL
Thread 0, Frame 0:
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions) returns void:
commandBuffer: VkCommandBuffer = 0x5651fe89b9f0
srcBuffer: VkBuffer = 0x5651ffcbf560
dstBuffer: VkBuffer = 0x5651fe986280
regionCount: uint32_t = 1
pRegions: const VkBufferCopy* = 0x7ffe711a6090
pRegions[0]: const VkBufferCopy = 0x7ffe711a6090:
srcOffset: VkDeviceSize = 0
dstOffset: VkDeviceSize = 0
size: VkDeviceSize = 1048576
For reference, I've uploaded the full API dump here.
The synchronization validation reports the following.
SYNC-HAZARD-READ-AFTER-WRITE(ERROR / SPEC): msgNum: -455515022 - Validation Error: [ SYNC-HAZARD-READ-AFTER-WRITE ] Object 0: handle = 0x55eebfc30cb0, type = VK_OBJECT_TYPE_BUFFER; | MessageID = 0xe4d96472 | vkCmdCopyBuffer: Hazard READ_AFTER_WRITE for srcBuffer VkBuffer 0x55eebfc30cb0[], region 0. Access info (usage: SYNC_COPY_TRANSFER_READ, prior_usage: SYNC_COMPUTE_SHADER_SHADER_STORAGE_WRITE, write_barriers: 0, command: vkCmdDispatch, seq_no: 1, reset_no: 1).
However, according to my understanding, the full pipeline barrier between the dispatch and the buffer copy (in command order) should avoid overlap between them also in execution order and with respect to memory visibility.
Notably, other validation areas (apart from "best practices") do not report any problems.
I'm at a loss what the validation error is supposed to tell me. Either I've made a very dumb small mistake which I cannot find, my understanding of synchronization is wrong or there is a bug in the validator.
It appears that this was a bug in the validation layers (present in version 1.3.236), that has been fixed in the latest release (1.3.239).