Skip to content

Commit 76310c3

Browse files
committed
Resolve read after write hazard in api samples [hpp_]oit_linked_lists.
1 parent ac9edc7 commit 76310c3

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

samples/api/hpp_oit_linked_lists/hpp_oit_linked_lists.cpp

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2023-2025, NVIDIA
1+
/* Copyright (c) 2023-2026, NVIDIA
22
*
33
* SPDX-License-Identifier: Apache-2.0
44
*
@@ -20,6 +20,8 @@
2020
HPPOITLinkedLists::HPPOITLinkedLists()
2121
{
2222
title = "HPP OIT linked lists";
23+
24+
add_device_extension(vk::KHRSynchronization2ExtensionName);
2325
}
2426

2527
HPPOITLinkedLists::~HPPOITLinkedLists()
@@ -94,6 +96,8 @@ void HPPOITLinkedLists::request_gpu_features(vkb::core::PhysicalDeviceCpp &gpu)
9496
{
9597
requested_features.samplerAnisotropy = true;
9698
}
99+
100+
REQUEST_REQUIRED_FEATURE(gpu, vk::PhysicalDeviceSynchronization2FeaturesKHR, synchronization2);
97101
}
98102

99103
void HPPOITLinkedLists::build_command_buffers()
@@ -132,15 +136,18 @@ void HPPOITLinkedLists::build_command_buffers()
132136
}
133137
command_buffer.endRenderPass();
134138

135-
vkb::common::image_layout_transition(command_buffer,
136-
linked_list_head_image->get_handle(),
137-
vk::PipelineStageFlagBits::eFragmentShader,
138-
vk::PipelineStageFlagBits::eFragmentShader,
139-
vk::AccessFlagBits::eShaderWrite,
140-
vk::AccessFlagBits::eShaderRead,
141-
vk::ImageLayout::eGeneral,
142-
vk::ImageLayout::eGeneral,
143-
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
139+
// Insert a pipeline barrier to ensure that all writes to the fragment buffer performed in the gather pass are made available before reading from it in the combine pass
140+
vk::BufferMemoryBarrier2 buffer_barrier{.srcStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
141+
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite,
142+
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
143+
.dstAccessMask = vk::AccessFlagBits2::eShaderStorageRead,
144+
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
145+
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
146+
.buffer = fragment_buffer->get_handle(),
147+
.offset = 0,
148+
.size = vk::WholeSize};
149+
vk::DependencyInfo dependency_info{.dependencyFlags = vk::DependencyFlagBits::eByRegion, .bufferMemoryBarrierCount = 1, .pBufferMemoryBarriers = &buffer_barrier};
150+
command_buffer.pipelineBarrier2(dependency_info);
144151

145152
// Combine pass
146153
combine_render_pass_begin_info.framebuffer = framebuffers[i];
@@ -270,21 +277,26 @@ void HPPOITLinkedLists::create_fragment_resources(vk::Extent2D const &extent)
270277
{
271278
const vk::Extent3D image_extent{extent.width, extent.height, 1};
272279
const vk::Format image_format{vk::Format::eR32Uint};
273-
linked_list_head_image = std::make_unique<vkb::core::HPPImage>(get_device(),
274-
image_extent,
275-
image_format,
276-
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst,
277-
VMA_MEMORY_USAGE_GPU_ONLY,
278-
vk::SampleCountFlagBits::e1);
280+
linked_list_head_image = std::make_unique<vkb::core::HPPImage>(get_device(),
281+
image_extent,
282+
image_format,
283+
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst,
284+
VMA_MEMORY_USAGE_GPU_ONLY,
285+
vk::SampleCountFlagBits::e1);
286+
linked_list_head_image->set_debug_name("linked_list_head_image");
287+
279288
linked_list_head_image_view = std::make_unique<vkb::core::HPPImageView>(*linked_list_head_image, vk::ImageViewType::e2D, image_format);
289+
linked_list_head_image_view->set_debug_name("linked_list_head_image_view");
280290

281291
fragment_max_count = extent.width * extent.height * kFragmentsPerPixelAverage;
282292
const uint32_t fragment_buffer_size = sizeof(glm::uvec3) * fragment_max_count;
283293
fragment_buffer =
284294
std::make_unique<vkb::core::BufferCpp>(get_device(), fragment_buffer_size, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_GPU_ONLY);
295+
fragment_buffer->set_debug_name("fragment_buffer");
285296

286297
fragment_counter = std::make_unique<vkb::core::BufferCpp>(
287298
get_device(), sizeof(glm::uint), vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, VMA_MEMORY_USAGE_GPU_ONLY);
299+
fragment_counter->set_debug_name("fragment_counter");
288300
}
289301

290302
void HPPOITLinkedLists::create_gather_pass_objects(vk::Extent2D const &extent)
@@ -448,8 +460,8 @@ void HPPOITLinkedLists::update_descriptors()
448460
vk::DescriptorBufferInfo fragment_buffer_descriptor{fragment_buffer->get_handle(), 0, vk::WholeSize};
449461
vk::DescriptorBufferInfo fragment_counter_descriptor{fragment_counter->get_handle(), 0, vk::WholeSize};
450462
vk::DescriptorImageInfo background_texture_descriptor{background_texture.sampler,
451-
background_texture.image->get_vk_image_view().get_handle(),
452-
descriptor_type_to_image_layout(vk::DescriptorType::eCombinedImageSampler,
463+
background_texture.image->get_vk_image_view().get_handle(),
464+
descriptor_type_to_image_layout(vk::DescriptorType::eCombinedImageSampler,
453465
background_texture.image->get_vk_image_view().get_format())};
454466

455467
std::array<vk::WriteDescriptorSet, 6> write_descriptor_sets = {{{.dstSet = descriptor_set,

samples/api/oit_linked_lists/oit_linked_lists.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2023-2025, Google
1+
/* Copyright (c) 2023-2026, Google
22
*
33
* SPDX-License-Identifier: Apache-2.0
44
*
@@ -20,6 +20,9 @@
2020

2121
OITLinkedLists::OITLinkedLists()
2222
{
23+
title = "OIT linked lists";
24+
25+
add_device_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
2326
}
2427

2528
OITLinkedLists::~OITLinkedLists()
@@ -115,6 +118,8 @@ void OITLinkedLists::request_gpu_features(vkb::core::PhysicalDeviceC &gpu)
115118
{
116119
throw std::runtime_error("This sample requires support for buffers and images stores and atomic operations in the fragment shader stage");
117120
}
121+
122+
REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceSynchronization2FeaturesKHR, synchronization2);
118123
}
119124

120125
void OITLinkedLists::on_update_ui_overlay(vkb::Drawer &drawer)
@@ -161,13 +166,19 @@ void OITLinkedLists::build_command_buffers()
161166
vkCmdEndRenderPass(draw_cmd_buffers[i]);
162167
}
163168

164-
VkImageSubresourceRange subresource_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
165-
vkb::image_layout_transition(
166-
draw_cmd_buffers[i], linked_list_head_image->get_handle(),
167-
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
168-
VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
169-
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
170-
subresource_range);
169+
// Insert a pipeline barrier to ensure that all writes to the fragment buffer performed in the gather pass are made available before reading from it in the combine pass
170+
VkBufferMemoryBarrier2 buffer_barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
171+
.srcStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
172+
.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
173+
.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
174+
.dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT,
175+
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
176+
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
177+
.buffer = fragment_buffer->get_handle(),
178+
.offset = 0,
179+
.size = VK_WHOLE_SIZE};
180+
VkDependencyInfo dependency_info{.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, .bufferMemoryBarrierCount = 1, .pBufferMemoryBarriers = &buffer_barrier};
181+
vkCmdPipelineBarrier2KHR(draw_cmd_buffers[i], &dependency_info);
171182

172183
// Combine pass
173184
{
@@ -252,17 +263,22 @@ void OITLinkedLists::create_fragment_resources(const uint32_t width, const uint3
252263
{
253264
const VkExtent3D image_extent = {width, height, 1};
254265
linked_list_head_image = std::make_unique<vkb::core::Image>(get_device(), image_extent, VK_FORMAT_R32_UINT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY, VK_SAMPLE_COUNT_1_BIT);
255-
linked_list_head_image_view = std::make_unique<vkb::core::ImageView>(*linked_list_head_image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32_UINT);
266+
linked_list_head_image->set_debug_name("linked_list_head_image");
267+
268+
linked_list_head_image_view = std::make_unique<vkb::core::ImageView>(*linked_list_head_image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32_UINT);
269+
linked_list_head_image_view->set_debug_name("linked_list_head_image_view");
256270
}
257271

258272
{
259273
fragment_max_count = width * height * kFragmentsPerPixelAverage;
260274
const uint32_t fragment_buffer_size = sizeof(glm::uvec3) * fragment_max_count;
261275
fragment_buffer = std::make_unique<vkb::core::BufferC>(get_device(), fragment_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
276+
fragment_buffer->set_debug_name("fragment_buffer");
262277
}
263278

264279
{
265280
fragment_counter = std::make_unique<vkb::core::BufferC>(get_device(), sizeof(glm::uint), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
281+
fragment_counter->set_debug_name("fragment_counter");
266282
}
267283
}
268284

0 commit comments

Comments
 (0)