Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8201e34

Browse files
committed
Fix source and destination pipeline stages in image pipeline barriers (fixes #60)
1 parent 23a7d43 commit 8201e34

7 files changed

Lines changed: 121 additions & 17 deletions

File tree

06_Texture_mapping/00_Images.md

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ back to this once we've figured out which transitions we're going to use.
520520
```c++
521521
vkCmdPipelineBarrier(
522522
commandBuffer,
523-
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
523+
0 /* TODO */, 0 /* TODO */,
524524
0,
525525
0, nullptr,
526526
0, nullptr,
@@ -529,10 +529,19 @@ vkCmdPipelineBarrier(
529529
```
530530

531531
All types of pipeline barriers are submitted using the same function. The first
532-
parameter specifies in which pipeline stage the operations occur that should
533-
happen before the barrier. The second parameter specifies the pipeline stage in
534-
which operations will wait on the barrier. We want it to happen immediately, so
535-
we're going with the top of the pipeline.
532+
parameter after the command buffer specifies in which pipeline stage the
533+
operations occur that should happen before the barrier. The second parameter
534+
specifies the pipeline stage in which operations will wait on the barrier. The
535+
pipeline stages that you are allowed to specify before and after the barrier
536+
depend on how you use the resource before and after the barrier. The allowed
537+
values are listed in [this table](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-access-types-supported)
538+
of the specification. For example, if you're going to read from a uniform after
539+
the barrier, you would specify a usage of `VK_ACCESS_UNIFORM_READ_BIT` and the
540+
earliest shader that will read from the uniform as pipeline stage, for example
541+
`VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT`. It would not make sense to specify
542+
a non-shader pipeline stage for this type of usage and the validation layers
543+
will warn you when you specify a pipeline stage that does not match the type of
544+
usage.
536545

537546
The third parameter is either `0` or `VK_DEPENDENCY_BY_REGION_BIT`. The latter
538547
turns the barrier into a per-region condition. That means that the
@@ -641,29 +650,59 @@ transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TR
641650
## Transition barrier masks
642651

643652
If run your application with validation layers enabled now, then you'll see that
644-
it complains about the access masks in `transitionImageLayout` being invalid.
645-
We still need to set those based on the layouts in the transition.
653+
it complains about the access masks and pipeline stages in
654+
`transitionImageLayout` being invalid. We still need to set those based on the
655+
layouts in the transition.
646656

647657
There are two transitions we need to handle:
648658

649-
* Undefined → transfer destination: transfer writes that don't need to wait
659+
* Undefined → transfer destination: transfer writes that don't need to wait on
660+
anything
650661
* Transfer destination → shader reading: shader reads should wait on transfer
651-
writes
662+
writes, specifically the shader reads in the fragment shader, because that's
663+
where we're going to use the texture
652664

653-
These rules are specified using the following access masks:
665+
These rules are specified using the following access masks and pipeline stages:
654666

655667
```c++
668+
VkPipelineStageFlags sourceStage;
669+
VkPipelineStageFlags destinationStage;
670+
656671
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
657672
barrier.srcAccessMask = 0;
658673
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
674+
675+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
676+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
659677
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
660678
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
661679
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
680+
681+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
682+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
662683
} else {
663684
throw std::invalid_argument("unsupported layout transition!");
664685
}
686+
687+
vkCmdPipelineBarrier(
688+
commandBuffer,
689+
sourceStage, destinationStage,
690+
0,
691+
0, nullptr,
692+
0, nullptr,
693+
1, &barrier
694+
);
665695
```
666696

697+
As you can see in the aforementioned table, transfer writes must occur in the
698+
pipeline transfer stage. Since the writes don't have to wait on anything, you
699+
may specify an empty access mask and the earliest possible pipeline stage
700+
`VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT` for the pre-barrier operations.
701+
702+
The image will be written in the same pipeline stage and subsequently read by
703+
the fragment shader, which is why we specify shader reading access in the
704+
fragment shader pipeline stage.
705+
667706
If we need to do more transitions in the future, then we'll extend the function.
668707
The application should now run successfully, although there are of course no
669708
visual changes yet.

07_Depth_buffering.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,24 +327,38 @@ if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
327327
Although we're not using the stencil component, we do need to include it in the
328328
layout transitions of the depth image.
329329

330-
Finally, add the correct access masks:
330+
Finally, add the correct access masks and pipeline stages:
331331

332332
```c++
333333
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
334334
barrier.srcAccessMask = 0;
335335
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
336+
337+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
338+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
336339
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
337340
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
338341
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
342+
343+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
344+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
339345
} else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
340346
barrier.srcAccessMask = 0;
341347
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
348+
349+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
350+
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
342351
} else {
343352
throw std::invalid_argument("unsupported layout transition!");
344353
}
345354
```
346355

347-
The image is now completely ready for usage as depth attachment.
356+
The depth buffer will be read from to perform depth tests to see if a fragment
357+
is visible, and will be written to when a new fragment is drawn. The reading
358+
happens in the `VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT` stage and the
359+
writing in the `VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT`. You should pick the
360+
earliest pipeline stage that matches the specified operations, so that it is
361+
ready for usage as depth attachment when it needs to be.
348362

349363
## Render pass
350364

code/depth_buffering.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -912,22 +912,34 @@ class HelloTriangleApplication {
912912
barrier.subresourceRange.baseArrayLayer = 0;
913913
barrier.subresourceRange.layerCount = 1;
914914

915+
VkPipelineStageFlags sourceStage;
916+
VkPipelineStageFlags destinationStage;
917+
915918
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
916919
barrier.srcAccessMask = 0;
917920
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
921+
922+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
923+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
918924
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
919925
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
920926
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
927+
928+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
929+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
921930
} else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
922931
barrier.srcAccessMask = 0;
923932
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
933+
934+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
935+
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
924936
} else {
925937
throw std::invalid_argument("unsupported layout transition!");
926938
}
927939

928940
vkCmdPipelineBarrier(
929941
commandBuffer,
930-
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
942+
sourceStage, destinationStage,
931943
0,
932944
0, nullptr,
933945
0, nullptr,

code/model_loading.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,22 +918,34 @@ class HelloTriangleApplication {
918918
barrier.subresourceRange.baseArrayLayer = 0;
919919
barrier.subresourceRange.layerCount = 1;
920920

921+
VkPipelineStageFlags sourceStage;
922+
VkPipelineStageFlags destinationStage;
923+
921924
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
922925
barrier.srcAccessMask = 0;
923926
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
927+
928+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
929+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
924930
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
925931
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
926932
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
933+
934+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
935+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
927936
} else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
928937
barrier.srcAccessMask = 0;
929938
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
939+
940+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
941+
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
930942
} else {
931943
throw std::invalid_argument("unsupported layout transition!");
932944
}
933945

934946
vkCmdPipelineBarrier(
935947
commandBuffer,
936-
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
948+
sourceStage, destinationStage,
937949
0,
938950
0, nullptr,
939951
0, nullptr,

code/sampler.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,19 +809,28 @@ class HelloTriangleApplication {
809809
barrier.subresourceRange.baseArrayLayer = 0;
810810
barrier.subresourceRange.layerCount = 1;
811811

812+
VkPipelineStageFlags sourceStage;
813+
VkPipelineStageFlags destinationStage;
814+
812815
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
813816
barrier.srcAccessMask = 0;
814817
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
818+
819+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
820+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
815821
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
816822
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
817823
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
824+
825+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
826+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
818827
} else {
819828
throw std::invalid_argument("unsupported layout transition!");
820829
}
821830

822831
vkCmdPipelineBarrier(
823832
commandBuffer,
824-
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
833+
sourceStage, destinationStage,
825834
0,
826835
0, nullptr,
827836
0, nullptr,

code/texture_image.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,19 +773,28 @@ class HelloTriangleApplication {
773773
barrier.subresourceRange.baseArrayLayer = 0;
774774
barrier.subresourceRange.layerCount = 1;
775775

776+
VkPipelineStageFlags sourceStage;
777+
VkPipelineStageFlags destinationStage;
778+
776779
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
777780
barrier.srcAccessMask = 0;
778781
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
782+
783+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
784+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
779785
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
780786
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
781787
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
788+
789+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
790+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
782791
} else {
783792
throw std::invalid_argument("unsupported layout transition!");
784793
}
785794

786795
vkCmdPipelineBarrier(
787796
commandBuffer,
788-
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
797+
sourceStage, destinationStage,
789798
0,
790799
0, nullptr,
791800
0, nullptr,

code/texture_mapping.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,19 +823,28 @@ class HelloTriangleApplication {
823823
barrier.subresourceRange.baseArrayLayer = 0;
824824
barrier.subresourceRange.layerCount = 1;
825825

826+
VkPipelineStageFlags sourceStage;
827+
VkPipelineStageFlags destinationStage;
828+
826829
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
827830
barrier.srcAccessMask = 0;
828831
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
832+
833+
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
834+
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
829835
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
830836
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
831837
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
838+
839+
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
840+
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
832841
} else {
833842
throw std::invalid_argument("unsupported layout transition!");
834843
}
835844

836845
vkCmdPipelineBarrier(
837846
commandBuffer,
838-
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
847+
sourceStage, destinationStage,
839848
0,
840849
0, nullptr,
841850
0, nullptr,

0 commit comments

Comments
 (0)