Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions samples/api/hpp_oit_linked_lists/hpp_oit_linked_lists.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2023-2025, NVIDIA
/* Copyright (c) 2023-2026, NVIDIA
*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -20,6 +20,8 @@
HPPOITLinkedLists::HPPOITLinkedLists()
{
title = "HPP OIT linked lists";

add_device_extension(vk::KHRSynchronization2ExtensionName);
}

HPPOITLinkedLists::~HPPOITLinkedLists()
Expand Down Expand Up @@ -94,6 +96,8 @@ void HPPOITLinkedLists::request_gpu_features(vkb::core::PhysicalDeviceCpp &gpu)
{
requested_features.samplerAnisotropy = true;
}

REQUEST_REQUIRED_FEATURE(gpu, vk::PhysicalDeviceSynchronization2FeaturesKHR, synchronization2);
}

void HPPOITLinkedLists::build_command_buffers()
Expand Down Expand Up @@ -132,15 +136,18 @@ void HPPOITLinkedLists::build_command_buffers()
}
command_buffer.endRenderPass();

vkb::common::image_layout_transition(command_buffer,
linked_list_head_image->get_handle(),
vk::PipelineStageFlagBits::eFragmentShader,
vk::PipelineStageFlagBits::eFragmentShader,
vk::AccessFlagBits::eShaderWrite,
vk::AccessFlagBits::eShaderRead,
vk::ImageLayout::eGeneral,
vk::ImageLayout::eGeneral,
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
// 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
vk::BufferMemoryBarrier2 buffer_barrier{.srcStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
.srcAccessMask = vk::AccessFlagBits2::eShaderStorageWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
.dstAccessMask = vk::AccessFlagBits2::eShaderStorageRead,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.buffer = fragment_buffer->get_handle(),
.offset = 0,
.size = vk::WholeSize};
vk::DependencyInfo dependency_info{.dependencyFlags = vk::DependencyFlagBits::eByRegion, .bufferMemoryBarrierCount = 1, .pBufferMemoryBarriers = &buffer_barrier};
command_buffer.pipelineBarrier2(dependency_info);
Copy link
Copy Markdown
Collaborator

@SaschaWillems SaschaWillems Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this works (due to the version baseline we use), shouldn't this be pipelineBarrier2KHR instead, as the sample explicitly requests the KHR sync2 extension? If this is supposed to use the non-KHR function, then there's no need to request the sync 2 KHR extension.


// Combine pass
combine_render_pass_begin_info.framebuffer = framebuffers[i];
Expand Down Expand Up @@ -270,21 +277,26 @@ void HPPOITLinkedLists::create_fragment_resources(vk::Extent2D const &extent)
{
const vk::Extent3D image_extent{extent.width, extent.height, 1};
const vk::Format image_format{vk::Format::eR32Uint};
linked_list_head_image = std::make_unique<vkb::core::HPPImage>(get_device(),
image_extent,
image_format,
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst,
VMA_MEMORY_USAGE_GPU_ONLY,
vk::SampleCountFlagBits::e1);
linked_list_head_image = std::make_unique<vkb::core::HPPImage>(get_device(),
image_extent,
image_format,
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst,
VMA_MEMORY_USAGE_GPU_ONLY,
vk::SampleCountFlagBits::e1);
linked_list_head_image->set_debug_name("linked_list_head_image");

linked_list_head_image_view = std::make_unique<vkb::core::HPPImageView>(*linked_list_head_image, vk::ImageViewType::e2D, image_format);
linked_list_head_image_view->set_debug_name("linked_list_head_image_view");

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

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

void HPPOITLinkedLists::create_gather_pass_objects(vk::Extent2D const &extent)
Expand Down
34 changes: 25 additions & 9 deletions samples/api/oit_linked_lists/oit_linked_lists.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2023-2025, Google
/* Copyright (c) 2023-2026, Google
*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -20,6 +20,9 @@

OITLinkedLists::OITLinkedLists()
{
title = "OIT linked lists";

add_device_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
}

OITLinkedLists::~OITLinkedLists()
Expand Down Expand Up @@ -115,6 +118,8 @@ void OITLinkedLists::request_gpu_features(vkb::core::PhysicalDeviceC &gpu)
{
throw std::runtime_error("This sample requires support for buffers and images stores and atomic operations in the fragment shader stage");
}

REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceSynchronization2FeaturesKHR, synchronization2);
}

void OITLinkedLists::on_update_ui_overlay(vkb::Drawer &drawer)
Expand Down Expand Up @@ -161,13 +166,19 @@ void OITLinkedLists::build_command_buffers()
vkCmdEndRenderPass(draw_cmd_buffers[i]);
}

VkImageSubresourceRange subresource_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vkb::image_layout_transition(
draw_cmd_buffers[i], linked_list_head_image->get_handle(),
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
subresource_range);
// 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
VkBufferMemoryBarrier2 buffer_barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
.dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = fragment_buffer->get_handle(),
.offset = 0,
.size = VK_WHOLE_SIZE};
VkDependencyInfo dependency_info{.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, .bufferMemoryBarrierCount = 1, .pBufferMemoryBarriers = &buffer_barrier};
vkCmdPipelineBarrier2KHR(draw_cmd_buffers[i], &dependency_info);

// Combine pass
{
Expand Down Expand Up @@ -252,17 +263,22 @@ void OITLinkedLists::create_fragment_resources(const uint32_t width, const uint3
{
const VkExtent3D image_extent = {width, height, 1};
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);
linked_list_head_image_view = std::make_unique<vkb::core::ImageView>(*linked_list_head_image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32_UINT);
linked_list_head_image->set_debug_name("linked_list_head_image");

linked_list_head_image_view = std::make_unique<vkb::core::ImageView>(*linked_list_head_image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32_UINT);
linked_list_head_image_view->set_debug_name("linked_list_head_image_view");
}

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

{
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);
fragment_counter->set_debug_name("fragment_counter");
}
}

Expand Down
Loading