2022-09-08 12:57:00 -06:00
/*
* Vulkan Example - Hardware accelerated ray tracing example using SBT data
*
* Uses the data section of each shader binding table record to color the background and geometry
*
* Copyright ( C ) 2019 - 2020 by Sascha Willems - www . saschawillems . de
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include "vulkanexamplebase.h"
// Holds data for a ray tracing scratch buffer that is used as a temporary storage
struct RayTracingScratchBuffer
{
uint64_t deviceAddress = 0 ;
VkBuffer handle = VK_NULL_HANDLE ;
VkDeviceMemory memory = VK_NULL_HANDLE ;
} ;
// Ray tracing acceleration structure
struct AccelerationStructure {
VkAccelerationStructureKHR handle ;
uint64_t deviceAddress = 0 ;
VkDeviceMemory memory ;
VkBuffer buffer ;
} ;
class VulkanExample : public VulkanExampleBase
{
public :
PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR ;
PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR ;
PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR ;
PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR ;
PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR ;
PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR ;
PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR ;
PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR ;
PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR ;
PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR ;
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties { } ;
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures { } ;
VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures { } ;
VkPhysicalDeviceRayTracingPipelineFeaturesKHR enabledRayTracingPipelineFeatures { } ;
VkPhysicalDeviceAccelerationStructureFeaturesKHR enabledAccelerationStructureFeatures { } ;
AccelerationStructure bottomLevelAS { } ;
AccelerationStructure topLevelAS { } ;
vks : : Buffer vertexBuffer ;
vks : : Buffer indexBuffer ;
uint32_t indexCount ;
vks : : Buffer transformBuffer ;
std : : vector < VkRayTracingShaderGroupCreateInfoKHR > shaderGroups { } ;
vks : : Buffer raygenShaderBindingTable ;
vks : : Buffer missShaderBindingTable ;
vks : : Buffer hitShaderBindingTable ;
struct StorageImage {
VkDeviceMemory memory ;
VkImage image ;
VkImageView view ;
VkFormat format ;
} storageImage ;
struct UniformData {
glm : : mat4 viewInverse ;
glm : : mat4 projInverse ;
} uniformData ;
vks : : Buffer ubo ;
VkPipeline pipeline ;
VkPipelineLayout pipelineLayout ;
VkDescriptorSet descriptorSet ;
VkDescriptorSetLayout descriptorSetLayout ;
VulkanExample ( ) : VulkanExampleBase ( )
{
title = " Ray tracing SBT data " ;
settings . overlay = false ;
camera . type = Camera : : CameraType : : lookat ;
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 512.0f ) ;
camera . setRotation ( glm : : vec3 ( 0.0f , 0.0f , 0.0f ) ) ;
camera . setTranslation ( glm : : vec3 ( 0.0f , 0.0f , - 2.5f ) ) ;
// Require Vulkan 1.1
apiVersion = VK_API_VERSION_1_1 ;
// Ray tracing related extensions required by this sample
enabledDeviceExtensions . push_back ( VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME ) ;
enabledDeviceExtensions . push_back ( VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME ) ;
// Required by VK_KHR_acceleration_structure
enabledDeviceExtensions . push_back ( VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME ) ;
enabledDeviceExtensions . push_back ( VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME ) ;
enabledDeviceExtensions . push_back ( VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME ) ;
// Required for VK_KHR_ray_tracing_pipeline
enabledDeviceExtensions . push_back ( VK_KHR_SPIRV_1_4_EXTENSION_NAME ) ;
// Required by VK_KHR_spirv_1_4
enabledDeviceExtensions . push_back ( VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME ) ;
}
~ VulkanExample ( )
{
vkDestroyPipeline ( device , pipeline , nullptr ) ;
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
vkDestroyImageView ( device , storageImage . view , nullptr ) ;
vkDestroyImage ( device , storageImage . image , nullptr ) ;
vkFreeMemory ( device , storageImage . memory , nullptr ) ;
vkFreeMemory ( device , bottomLevelAS . memory , nullptr ) ;
vkDestroyBuffer ( device , bottomLevelAS . buffer , nullptr ) ;
vkDestroyAccelerationStructureKHR ( device , bottomLevelAS . handle , nullptr ) ;
vkFreeMemory ( device , topLevelAS . memory , nullptr ) ;
vkDestroyBuffer ( device , topLevelAS . buffer , nullptr ) ;
vkDestroyAccelerationStructureKHR ( device , topLevelAS . handle , nullptr ) ;
vertexBuffer . destroy ( ) ;
indexBuffer . destroy ( ) ;
transformBuffer . destroy ( ) ;
raygenShaderBindingTable . destroy ( ) ;
missShaderBindingTable . destroy ( ) ;
hitShaderBindingTable . destroy ( ) ;
ubo . destroy ( ) ;
}
/*
Create a scratch buffer to hold temporary data for a ray tracing acceleration structure
*/
RayTracingScratchBuffer createScratchBuffer ( VkDeviceSize size )
{
RayTracingScratchBuffer scratchBuffer { } ;
VkBufferCreateInfo bufferCreateInfo { } ;
bufferCreateInfo . sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO ;
bufferCreateInfo . size = size ;
bufferCreateInfo . usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ;
VK_CHECK_RESULT ( vkCreateBuffer ( device , & bufferCreateInfo , nullptr , & scratchBuffer . handle ) ) ;
VkMemoryRequirements memoryRequirements { } ;
vkGetBufferMemoryRequirements ( device , scratchBuffer . handle , & memoryRequirements ) ;
VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo { } ;
memoryAllocateFlagsInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO ;
memoryAllocateFlagsInfo . flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR ;
VkMemoryAllocateInfo memoryAllocateInfo = { } ;
memoryAllocateInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memoryAllocateInfo . pNext = & memoryAllocateFlagsInfo ;
memoryAllocateInfo . allocationSize = memoryRequirements . size ;
memoryAllocateInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memoryRequirements . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memoryAllocateInfo , nullptr , & scratchBuffer . memory ) ) ;
VK_CHECK_RESULT ( vkBindBufferMemory ( device , scratchBuffer . handle , scratchBuffer . memory , 0 ) ) ;
VkBufferDeviceAddressInfoKHR bufferDeviceAddressInfo { } ;
bufferDeviceAddressInfo . sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO ;
bufferDeviceAddressInfo . buffer = scratchBuffer . handle ;
scratchBuffer . deviceAddress = vkGetBufferDeviceAddressKHR ( device , & bufferDeviceAddressInfo ) ;
return scratchBuffer ;
}
void deleteScratchBuffer ( RayTracingScratchBuffer & scratchBuffer )
{
if ( scratchBuffer . memory ! = VK_NULL_HANDLE ) {
vkFreeMemory ( device , scratchBuffer . memory , nullptr ) ;
}
if ( scratchBuffer . handle ! = VK_NULL_HANDLE ) {
vkDestroyBuffer ( device , scratchBuffer . handle , nullptr ) ;
}
}
void createAccelerationStructureBuffer ( AccelerationStructure & accelerationStructure , VkAccelerationStructureBuildSizesInfoKHR buildSizeInfo )
{
VkBufferCreateInfo bufferCreateInfo { } ;
bufferCreateInfo . sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO ;
bufferCreateInfo . size = buildSizeInfo . accelerationStructureSize ;
bufferCreateInfo . usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ;
VK_CHECK_RESULT ( vkCreateBuffer ( device , & bufferCreateInfo , nullptr , & accelerationStructure . buffer ) ) ;
VkMemoryRequirements memoryRequirements { } ;
vkGetBufferMemoryRequirements ( device , accelerationStructure . buffer , & memoryRequirements ) ;
VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo { } ;
memoryAllocateFlagsInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO ;
memoryAllocateFlagsInfo . flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR ;
VkMemoryAllocateInfo memoryAllocateInfo { } ;
memoryAllocateInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memoryAllocateInfo . pNext = & memoryAllocateFlagsInfo ;
memoryAllocateInfo . allocationSize = memoryRequirements . size ;
memoryAllocateInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memoryRequirements . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memoryAllocateInfo , nullptr , & accelerationStructure . memory ) ) ;
VK_CHECK_RESULT ( vkBindBufferMemory ( device , accelerationStructure . buffer , accelerationStructure . memory , 0 ) ) ;
}
/*
Gets the device address from a buffer that ' s required for some of the buffers used for ray tracing
*/
uint64_t getBufferDeviceAddress ( VkBuffer buffer )
{
VkBufferDeviceAddressInfoKHR bufferDeviceAI { } ;
bufferDeviceAI . sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO ;
bufferDeviceAI . buffer = buffer ;
return vkGetBufferDeviceAddressKHR ( device , & bufferDeviceAI ) ;
}
/*
Set up a storage image that the ray generation shader will be writing to
*/
void createStorageImage ( )
{
VkImageCreateInfo image = vks : : initializers : : imageCreateInfo ( ) ;
image . imageType = VK_IMAGE_TYPE_2D ;
image . format = swapChain . colorFormat ;
image . extent . width = width ;
image . extent . height = height ;
image . extent . depth = 1 ;
image . mipLevels = 1 ;
image . arrayLayers = 1 ;
image . samples = VK_SAMPLE_COUNT_1_BIT ;
image . tiling = VK_IMAGE_TILING_OPTIMAL ;
image . usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT ;
image . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
VK_CHECK_RESULT ( vkCreateImage ( device , & image , nullptr , & storageImage . image ) ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , storageImage . image , & memReqs ) ;
VkMemoryAllocateInfo memoryAllocateInfo = vks : : initializers : : memoryAllocateInfo ( ) ;
memoryAllocateInfo . allocationSize = memReqs . size ;
memoryAllocateInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memoryAllocateInfo , nullptr , & storageImage . memory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , storageImage . image , storageImage . memory , 0 ) ) ;
VkImageViewCreateInfo colorImageView = vks : : initializers : : imageViewCreateInfo ( ) ;
colorImageView . viewType = VK_IMAGE_VIEW_TYPE_2D ;
colorImageView . format = swapChain . colorFormat ;
colorImageView . subresourceRange = { } ;
colorImageView . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
colorImageView . subresourceRange . baseMipLevel = 0 ;
colorImageView . subresourceRange . levelCount = 1 ;
colorImageView . subresourceRange . baseArrayLayer = 0 ;
colorImageView . subresourceRange . layerCount = 1 ;
colorImageView . image = storageImage . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & colorImageView , nullptr , & storageImage . view ) ) ;
VkCommandBuffer cmdBuffer = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
vks : : tools : : setImageLayout ( cmdBuffer , storageImage . image ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_GENERAL ,
{ VK_IMAGE_ASPECT_COLOR_BIT , 0 , 1 , 0 , 1 } ) ;
vulkanDevice - > flushCommandBuffer ( cmdBuffer , queue ) ;
}
/*
Create the bottom level acceleration structure contains the scene ' s actual geometry ( vertices , triangles )
*/
void createBottomLevelAccelerationStructure ( )
{
// Setup vertices for a single triangle
struct Vertex {
float pos [ 3 ] ;
} ;
std : : vector < Vertex > vertices = {
{ { 1.0f , 1.0f , 0.0f } } ,
{ { - 1.0f , 1.0f , 0.0f } } ,
{ { 0.0f , - 1.0f , 0.0f } }
} ;
// Setup indices
std : : vector < uint32_t > indices = { 0 , 1 , 2 } ;
indexCount = static_cast < uint32_t > ( indices . size ( ) ) ;
// Setup identity transform matrix
VkTransformMatrixKHR transformMatrix = {
1.0f , 0.0f , 0.0f , 0.0f ,
0.0f , 1.0f , 0.0f , 0.0f ,
0.0f , 0.0f , 1.0f , 0.0f
} ;
// Create buffers
// For the sake of simplicity we won't stage the vertex data to the GPU memory
// Vertex buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& vertexBuffer ,
vertices . size ( ) * sizeof ( Vertex ) ,
vertices . data ( ) ) ) ;
// Index buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& indexBuffer ,
indices . size ( ) * sizeof ( uint32_t ) ,
indices . data ( ) ) ) ;
// Transform buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& transformBuffer ,
sizeof ( VkTransformMatrixKHR ) ,
& transformMatrix ) ) ;
VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress { } ;
VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress { } ;
VkDeviceOrHostAddressConstKHR transformBufferDeviceAddress { } ;
vertexBufferDeviceAddress . deviceAddress = getBufferDeviceAddress ( vertexBuffer . buffer ) ;
indexBufferDeviceAddress . deviceAddress = getBufferDeviceAddress ( indexBuffer . buffer ) ;
transformBufferDeviceAddress . deviceAddress = getBufferDeviceAddress ( transformBuffer . buffer ) ;
// Build
VkAccelerationStructureGeometryKHR accelerationStructureGeometry { } ;
accelerationStructureGeometry . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR ;
accelerationStructureGeometry . flags = VK_GEOMETRY_OPAQUE_BIT_KHR ;
accelerationStructureGeometry . geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR ;
accelerationStructureGeometry . geometry . triangles . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR ;
accelerationStructureGeometry . geometry . triangles . vertexFormat = VK_FORMAT_R32G32B32_SFLOAT ;
accelerationStructureGeometry . geometry . triangles . vertexData = vertexBufferDeviceAddress ;
accelerationStructureGeometry . geometry . triangles . maxVertex = 3 ;
accelerationStructureGeometry . geometry . triangles . vertexStride = sizeof ( Vertex ) ;
accelerationStructureGeometry . geometry . triangles . indexType = VK_INDEX_TYPE_UINT32 ;
accelerationStructureGeometry . geometry . triangles . indexData = indexBufferDeviceAddress ;
accelerationStructureGeometry . geometry . triangles . transformData . deviceAddress = 0 ;
accelerationStructureGeometry . geometry . triangles . transformData . hostAddress = nullptr ;
accelerationStructureGeometry . geometry . triangles . transformData = transformBufferDeviceAddress ;
// Get size info
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo { } ;
accelerationStructureBuildGeometryInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR ;
accelerationStructureBuildGeometryInfo . type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR ;
accelerationStructureBuildGeometryInfo . flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR ;
accelerationStructureBuildGeometryInfo . geometryCount = 1 ;
accelerationStructureBuildGeometryInfo . pGeometries = & accelerationStructureGeometry ;
const uint32_t numTriangles = 1 ;
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo { } ;
accelerationStructureBuildSizesInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR ;
vkGetAccelerationStructureBuildSizesKHR (
device ,
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR ,
& accelerationStructureBuildGeometryInfo ,
& numTriangles ,
& accelerationStructureBuildSizesInfo ) ;
createAccelerationStructureBuffer ( bottomLevelAS , accelerationStructureBuildSizesInfo ) ;
VkAccelerationStructureCreateInfoKHR accelerationStructureCreateInfo { } ;
accelerationStructureCreateInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR ;
accelerationStructureCreateInfo . buffer = bottomLevelAS . buffer ;
accelerationStructureCreateInfo . size = accelerationStructureBuildSizesInfo . accelerationStructureSize ;
accelerationStructureCreateInfo . type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR ;
vkCreateAccelerationStructureKHR ( device , & accelerationStructureCreateInfo , nullptr , & bottomLevelAS . handle ) ;
// Create a small scratch buffer used during build of the bottom level acceleration structure
RayTracingScratchBuffer scratchBuffer = createScratchBuffer ( accelerationStructureBuildSizesInfo . buildScratchSize ) ;
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo { } ;
accelerationBuildGeometryInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR ;
accelerationBuildGeometryInfo . type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR ;
accelerationBuildGeometryInfo . flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR ;
accelerationBuildGeometryInfo . mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR ;
accelerationBuildGeometryInfo . dstAccelerationStructure = bottomLevelAS . handle ;
accelerationBuildGeometryInfo . geometryCount = 1 ;
accelerationBuildGeometryInfo . pGeometries = & accelerationStructureGeometry ;
accelerationBuildGeometryInfo . scratchData . deviceAddress = scratchBuffer . deviceAddress ;
VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo { } ;
accelerationStructureBuildRangeInfo . primitiveCount = numTriangles ;
accelerationStructureBuildRangeInfo . primitiveOffset = 0 ;
accelerationStructureBuildRangeInfo . firstVertex = 0 ;
accelerationStructureBuildRangeInfo . transformOffset = 0 ;
std : : vector < VkAccelerationStructureBuildRangeInfoKHR * > accelerationBuildStructureRangeInfos = { & accelerationStructureBuildRangeInfo } ;
// Build the acceleration structure on the device via a one-time command buffer submission
// Some implementations may support acceleration structure building on the host (VkPhysicalDeviceAccelerationStructureFeaturesKHR->accelerationStructureHostCommands), but we prefer device builds
VkCommandBuffer commandBuffer = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
vkCmdBuildAccelerationStructuresKHR (
commandBuffer ,
1 ,
& accelerationBuildGeometryInfo ,
accelerationBuildStructureRangeInfos . data ( ) ) ;
vulkanDevice - > flushCommandBuffer ( commandBuffer , queue ) ;
VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo { } ;
accelerationDeviceAddressInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR ;
accelerationDeviceAddressInfo . accelerationStructure = bottomLevelAS . handle ;
bottomLevelAS . deviceAddress = vkGetAccelerationStructureDeviceAddressKHR ( device , & accelerationDeviceAddressInfo ) ;
deleteScratchBuffer ( scratchBuffer ) ;
}
/*
The top level acceleration structure contains the scene ' s object instances
*/
void createTopLevelAccelerationStructure ( )
{
VkTransformMatrixKHR transformMatrix = {
1.0f , 0.0f , 0.0f , 0.0f ,
0.0f , 1.0f , 0.0f , 0.0f ,
0.0f , 0.0f , 1.0f , 0.0f } ;
VkAccelerationStructureInstanceKHR instance { } ;
instance . transform = transformMatrix ;
instance . instanceCustomIndex = 0 ;
instance . mask = 0xFF ;
instance . instanceShaderBindingTableRecordOffset = 0 ;
instance . flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR ;
instance . accelerationStructureReference = bottomLevelAS . deviceAddress ;
// Buffer for instance data
vks : : Buffer instancesBuffer ;
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& instancesBuffer ,
sizeof ( VkAccelerationStructureInstanceKHR ) ,
& instance ) ) ;
VkDeviceOrHostAddressConstKHR instanceDataDeviceAddress { } ;
instanceDataDeviceAddress . deviceAddress = getBufferDeviceAddress ( instancesBuffer . buffer ) ;
VkAccelerationStructureGeometryKHR accelerationStructureGeometry { } ;
accelerationStructureGeometry . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR ;
accelerationStructureGeometry . geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR ;
accelerationStructureGeometry . flags = VK_GEOMETRY_OPAQUE_BIT_KHR ;
accelerationStructureGeometry . geometry . instances . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR ;
accelerationStructureGeometry . geometry . instances . arrayOfPointers = VK_FALSE ;
accelerationStructureGeometry . geometry . instances . data = instanceDataDeviceAddress ;
// Get size info
/*
The pSrcAccelerationStructure , dstAccelerationStructure , and mode members of pBuildInfo are ignored . Any VkDeviceOrHostAddressKHR members of pBuildInfo are ignored by this command , except that the hostAddress member of VkAccelerationStructureGeometryTrianglesDataKHR : : transformData will be examined to check if it is NULL . *
*/
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo { } ;
accelerationStructureBuildGeometryInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR ;
accelerationStructureBuildGeometryInfo . type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR ;
accelerationStructureBuildGeometryInfo . flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR ;
accelerationStructureBuildGeometryInfo . geometryCount = 1 ;
accelerationStructureBuildGeometryInfo . pGeometries = & accelerationStructureGeometry ;
uint32_t primitive_count = 1 ;
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo { } ;
accelerationStructureBuildSizesInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR ;
vkGetAccelerationStructureBuildSizesKHR (
device ,
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR ,
& accelerationStructureBuildGeometryInfo ,
& primitive_count ,
& accelerationStructureBuildSizesInfo ) ;
createAccelerationStructureBuffer ( topLevelAS , accelerationStructureBuildSizesInfo ) ;
VkAccelerationStructureCreateInfoKHR accelerationStructureCreateInfo { } ;
accelerationStructureCreateInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR ;
accelerationStructureCreateInfo . buffer = topLevelAS . buffer ;
accelerationStructureCreateInfo . size = accelerationStructureBuildSizesInfo . accelerationStructureSize ;
accelerationStructureCreateInfo . type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR ;
vkCreateAccelerationStructureKHR ( device , & accelerationStructureCreateInfo , nullptr , & topLevelAS . handle ) ;
// Create a small scratch buffer used during build of the top level acceleration structure
RayTracingScratchBuffer scratchBuffer = createScratchBuffer ( accelerationStructureBuildSizesInfo . buildScratchSize ) ;
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo { } ;
accelerationBuildGeometryInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR ;
accelerationBuildGeometryInfo . type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR ;
accelerationBuildGeometryInfo . flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR ;
accelerationBuildGeometryInfo . mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR ;
accelerationBuildGeometryInfo . dstAccelerationStructure = topLevelAS . handle ;
accelerationBuildGeometryInfo . geometryCount = 1 ;
accelerationBuildGeometryInfo . pGeometries = & accelerationStructureGeometry ;
accelerationBuildGeometryInfo . scratchData . deviceAddress = scratchBuffer . deviceAddress ;
VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo { } ;
accelerationStructureBuildRangeInfo . primitiveCount = 1 ;
accelerationStructureBuildRangeInfo . primitiveOffset = 0 ;
accelerationStructureBuildRangeInfo . firstVertex = 0 ;
accelerationStructureBuildRangeInfo . transformOffset = 0 ;
std : : vector < VkAccelerationStructureBuildRangeInfoKHR * > accelerationBuildStructureRangeInfos = { & accelerationStructureBuildRangeInfo } ;
// Build the acceleration structure on the device via a one-time command buffer submission
// Some implementations may support acceleration structure building on the host (VkPhysicalDeviceAccelerationStructureFeaturesKHR->accelerationStructureHostCommands), but we prefer device builds
VkCommandBuffer commandBuffer = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
vkCmdBuildAccelerationStructuresKHR (
commandBuffer ,
1 ,
& accelerationBuildGeometryInfo ,
accelerationBuildStructureRangeInfos . data ( ) ) ;
vulkanDevice - > flushCommandBuffer ( commandBuffer , queue ) ;
VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo { } ;
accelerationDeviceAddressInfo . sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR ;
accelerationDeviceAddressInfo . accelerationStructure = topLevelAS . handle ;
topLevelAS . deviceAddress = vkGetAccelerationStructureDeviceAddressKHR ( device , & accelerationDeviceAddressInfo ) ;
deleteScratchBuffer ( scratchBuffer ) ;
instancesBuffer . destroy ( ) ;
}
/*
Create the Shader Binding Tables that binds the programs and top - level acceleration structure
SBT Layout used in this sample :
/ - - - - - - - - - - - \
| raygen |
| - - - - - - - - - - - |
| miss |
| - - - - - - - - - - - |
| hit |
\ - - - - - - - - - - - /
*/
void createShaderBindingTable ( ) {
const uint32_t handleSize = rayTracingPipelineProperties . shaderGroupHandleSize ;
const uint32_t handleSizeAligned = vks : : tools : : alignedSize ( rayTracingPipelineProperties . shaderGroupHandleSize , rayTracingPipelineProperties . shaderGroupHandleAlignment ) ;
const uint32_t groupCount = static_cast < uint32_t > ( shaderGroups . size ( ) ) ;
const uint32_t sbtSize = groupCount * handleSizeAligned ;
std : : vector < uint8_t > shaderHandleStorage ( sbtSize ) ;
VK_CHECK_RESULT ( vkGetRayTracingShaderGroupHandlesKHR ( device , pipeline , 0 , groupCount , sbtSize , shaderHandleStorage . data ( ) ) ) ;
const VkBufferUsageFlags bufferUsageFlags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ;
const VkMemoryPropertyFlags memoryUsageFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ;
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( bufferUsageFlags , memoryUsageFlags , & raygenShaderBindingTable , handleSize + sizeof ( float ) * 3 ) ) ;
2022-09-09 11:54:26 -06:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( bufferUsageFlags , memoryUsageFlags , & missShaderBindingTable , handleSize ) ) ;
2022-09-08 12:57:00 -06:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer ( bufferUsageFlags , memoryUsageFlags , & hitShaderBindingTable , handleSize + sizeof ( float ) * 3 ) ) ;
// Copy handles
raygenShaderBindingTable . map ( ) ;
missShaderBindingTable . map ( ) ;
hitShaderBindingTable . map ( ) ;
memcpy ( raygenShaderBindingTable . mapped , shaderHandleStorage . data ( ) , handleSize ) ;
memcpy ( missShaderBindingTable . mapped , shaderHandleStorage . data ( ) + handleSizeAligned , handleSize ) ;
memcpy ( hitShaderBindingTable . mapped , shaderHandleStorage . data ( ) + handleSizeAligned * 2 , handleSize ) ;
// set raygen sbt colors
{
glm : : vec3 color ( 1.f , 0.f , 0.f ) ;
memcpy ( ( ( uint8_t * ) ( raygenShaderBindingTable . mapped ) ) + handleSize , & color , sizeof ( glm : : vec3 ) ) ;
}
// set chit sbt colors
{
glm : : vec3 color ( 0.f , 1.f , 0.f ) ;
memcpy ( ( ( uint8_t * ) ( hitShaderBindingTable . mapped ) ) + handleSize , & color , sizeof ( glm : : vec3 ) ) ;
}
}
/*
Create the descriptor sets used for the ray tracing dispatch
*/
void createDescriptorSets ( )
{
std : : vector < VkDescriptorPoolSize > poolSizes = {
{ VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR , 1 } ,
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE , 1 } ,
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 }
} ;
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 1 ) ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolCreateInfo , nullptr , & descriptorPool ) ) ;
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayout , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & descriptorSetAllocateInfo , & descriptorSet ) ) ;
VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo { } ;
descriptorAccelerationStructureInfo . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR ;
descriptorAccelerationStructureInfo . accelerationStructureCount = 1 ;
descriptorAccelerationStructureInfo . pAccelerationStructures = & topLevelAS . handle ;
VkWriteDescriptorSet accelerationStructureWrite { } ;
accelerationStructureWrite . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
// The specialized acceleration structure descriptor has to be chained
accelerationStructureWrite . pNext = & descriptorAccelerationStructureInfo ;
accelerationStructureWrite . dstSet = descriptorSet ;
accelerationStructureWrite . dstBinding = 0 ;
accelerationStructureWrite . descriptorCount = 1 ;
accelerationStructureWrite . descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ;
VkDescriptorImageInfo storageImageDescriptor { } ;
storageImageDescriptor . imageView = storageImage . view ;
storageImageDescriptor . imageLayout = VK_IMAGE_LAYOUT_GENERAL ;
VkWriteDescriptorSet resultImageWrite = vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_STORAGE_IMAGE , 1 , & storageImageDescriptor ) ;
VkWriteDescriptorSet uniformBufferWrite = vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 2 , & ubo . descriptor ) ;
std : : vector < VkWriteDescriptorSet > writeDescriptorSets = {
accelerationStructureWrite ,
resultImageWrite ,
uniformBufferWrite
} ;
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , VK_NULL_HANDLE ) ;
}
/*
Create our ray tracing pipeline
*/
void createRayTracingPipeline ( )
{
VkDescriptorSetLayoutBinding accelerationStructureLayoutBinding { } ;
accelerationStructureLayoutBinding . binding = 0 ;
accelerationStructureLayoutBinding . descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ;
accelerationStructureLayoutBinding . descriptorCount = 1 ;
accelerationStructureLayoutBinding . stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR ;
VkDescriptorSetLayoutBinding resultImageLayoutBinding { } ;
resultImageLayoutBinding . binding = 1 ;
resultImageLayoutBinding . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ;
resultImageLayoutBinding . descriptorCount = 1 ;
resultImageLayoutBinding . stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR ;
VkDescriptorSetLayoutBinding uniformBufferBinding { } ;
uniformBufferBinding . binding = 2 ;
uniformBufferBinding . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
uniformBufferBinding . descriptorCount = 1 ;
uniformBufferBinding . stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR ;
std : : vector < VkDescriptorSetLayoutBinding > bindings ( {
accelerationStructureLayoutBinding ,
resultImageLayoutBinding ,
uniformBufferBinding
} ) ;
VkDescriptorSetLayoutCreateInfo descriptorSetlayoutCI { } ;
descriptorSetlayoutCI . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
descriptorSetlayoutCI . bindingCount = static_cast < uint32_t > ( bindings . size ( ) ) ;
descriptorSetlayoutCI . pBindings = bindings . data ( ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetlayoutCI , nullptr , & descriptorSetLayout ) ) ;
VkPipelineLayoutCreateInfo pipelineLayoutCI { } ;
pipelineLayoutCI . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
pipelineLayoutCI . setLayoutCount = 1 ;
pipelineLayoutCI . pSetLayouts = & descriptorSetLayout ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelineLayout ) ) ;
/*
Setup ray tracing shader groups
*/
std : : vector < VkPipelineShaderStageCreateInfo > shaderStages ;
// Ray generation group
{
shaderStages . push_back ( loadShader ( getShadersPath ( ) + " raytracingsbtdata/raygen.rgen.spv " , VK_SHADER_STAGE_RAYGEN_BIT_KHR ) ) ;
VkRayTracingShaderGroupCreateInfoKHR shaderGroup { } ;
shaderGroup . sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR ;
shaderGroup . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR ;
shaderGroup . generalShader = static_cast < uint32_t > ( shaderStages . size ( ) ) - 1 ;
shaderGroup . closestHitShader = VK_SHADER_UNUSED_KHR ;
shaderGroup . anyHitShader = VK_SHADER_UNUSED_KHR ;
shaderGroup . intersectionShader = VK_SHADER_UNUSED_KHR ;
shaderGroups . push_back ( shaderGroup ) ;
}
// Miss group
{
shaderStages . push_back ( loadShader ( getShadersPath ( ) + " raytracingsbtdata/miss.rmiss.spv " , VK_SHADER_STAGE_MISS_BIT_KHR ) ) ;
VkRayTracingShaderGroupCreateInfoKHR shaderGroup { } ;
shaderGroup . sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR ;
shaderGroup . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR ;
shaderGroup . generalShader = static_cast < uint32_t > ( shaderStages . size ( ) ) - 1 ;
shaderGroup . closestHitShader = VK_SHADER_UNUSED_KHR ;
shaderGroup . anyHitShader = VK_SHADER_UNUSED_KHR ;
shaderGroup . intersectionShader = VK_SHADER_UNUSED_KHR ;
shaderGroups . push_back ( shaderGroup ) ;
}
// Closest hit group
{
shaderStages . push_back ( loadShader ( getShadersPath ( ) + " raytracingsbtdata/closesthit.rchit.spv " , VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ) ) ;
VkRayTracingShaderGroupCreateInfoKHR shaderGroup { } ;
shaderGroup . sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR ;
shaderGroup . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR ;
shaderGroup . generalShader = VK_SHADER_UNUSED_KHR ;
shaderGroup . closestHitShader = static_cast < uint32_t > ( shaderStages . size ( ) ) - 1 ;
shaderGroup . anyHitShader = VK_SHADER_UNUSED_KHR ;
shaderGroup . intersectionShader = VK_SHADER_UNUSED_KHR ;
shaderGroups . push_back ( shaderGroup ) ;
}
/*
Create the ray tracing pipeline
*/
VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI { } ;
rayTracingPipelineCI . sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR ;
rayTracingPipelineCI . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
rayTracingPipelineCI . pStages = shaderStages . data ( ) ;
rayTracingPipelineCI . groupCount = static_cast < uint32_t > ( shaderGroups . size ( ) ) ;
rayTracingPipelineCI . pGroups = shaderGroups . data ( ) ;
rayTracingPipelineCI . maxPipelineRayRecursionDepth = 1 ;
rayTracingPipelineCI . layout = pipelineLayout ;
VK_CHECK_RESULT ( vkCreateRayTracingPipelinesKHR ( device , VK_NULL_HANDLE , VK_NULL_HANDLE , 1 , & rayTracingPipelineCI , nullptr , & pipeline ) ) ;
}
/*
Create the uniform buffer used to pass matrices to the ray tracing ray generation shader
*/
void createUniformBuffer ( )
{
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& ubo ,
sizeof ( uniformData ) ,
& uniformData ) ) ;
VK_CHECK_RESULT ( ubo . map ( ) ) ;
updateUniformBuffers ( ) ;
}
/*
If the window has been resized , we need to recreate the storage image and it ' s descriptor
*/
void handleResize ( )
{
// Delete allocated resources
vkDestroyImageView ( device , storageImage . view , nullptr ) ;
vkDestroyImage ( device , storageImage . image , nullptr ) ;
vkFreeMemory ( device , storageImage . memory , nullptr ) ;
// Recreate image
createStorageImage ( ) ;
// Update descriptor
VkDescriptorImageInfo storageImageDescriptor { VK_NULL_HANDLE , storageImage . view , VK_IMAGE_LAYOUT_GENERAL } ;
VkWriteDescriptorSet resultImageWrite = vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_STORAGE_IMAGE , 1 , & storageImageDescriptor ) ;
vkUpdateDescriptorSets ( device , 1 , & resultImageWrite , 0 , VK_NULL_HANDLE ) ;
}
/*
Command buffer generation
*/
void buildCommandBuffers ( )
{
if ( resized )
{
handleResize ( ) ;
}
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 1 , 0 , 1 } ;
for ( int32_t i = 0 ; i < drawCmdBuffers . size ( ) ; + + i )
{
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
/*
Setup the buffer regions pointing to the shaders in our shader binding table
*/
const uint32_t handleSizeAligned = vks : : tools : : alignedSize ( rayTracingPipelineProperties . shaderGroupHandleSize , rayTracingPipelineProperties . shaderGroupHandleAlignment ) ;
VkStridedDeviceAddressRegionKHR raygenShaderSbtEntry { } ;
raygenShaderSbtEntry . deviceAddress = getBufferDeviceAddress ( raygenShaderBindingTable . buffer ) ;
raygenShaderSbtEntry . stride = handleSizeAligned ;
2022-09-09 11:54:26 -06:00
raygenShaderSbtEntry . size = vks : : tools : : alignedSize ( handleSizeAligned + 3 * sizeof ( float ) , rayTracingPipelineProperties . shaderGroupBaseAlignment ) ;
2022-09-08 12:57:00 -06:00
VkStridedDeviceAddressRegionKHR missShaderSbtEntry { } ;
missShaderSbtEntry . deviceAddress = getBufferDeviceAddress ( missShaderBindingTable . buffer ) ;
missShaderSbtEntry . stride = handleSizeAligned ;
missShaderSbtEntry . size = handleSizeAligned ;
VkStridedDeviceAddressRegionKHR hitShaderSbtEntry { } ;
hitShaderSbtEntry . deviceAddress = getBufferDeviceAddress ( hitShaderBindingTable . buffer ) ;
hitShaderSbtEntry . stride = handleSizeAligned ;
2022-09-09 11:54:26 -06:00
hitShaderSbtEntry . size = vks : : tools : : alignedSize ( handleSizeAligned + 3 * sizeof ( float ) , rayTracingPipelineProperties . shaderGroupBaseAlignment ) ;
2022-09-08 12:57:00 -06:00
VkStridedDeviceAddressRegionKHR callableShaderSbtEntry { } ;
/*
Dispatch the ray tracing commands
*/
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR , pipeline ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR , pipelineLayout , 0 , 1 , & descriptorSet , 0 , 0 ) ;
vkCmdTraceRaysKHR (
drawCmdBuffers [ i ] ,
& raygenShaderSbtEntry ,
& missShaderSbtEntry ,
& hitShaderSbtEntry ,
& callableShaderSbtEntry ,
width ,
height ,
1 ) ;
/*
Copy ray tracing output to swap chain image
*/
// Prepare current swap chain image as transfer destination
vks : : tools : : setImageLayout (
drawCmdBuffers [ i ] ,
swapChain . images [ i ] ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
subresourceRange ) ;
// Prepare ray tracing output image as transfer source
vks : : tools : : setImageLayout (
drawCmdBuffers [ i ] ,
storageImage . image ,
VK_IMAGE_LAYOUT_GENERAL ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ,
subresourceRange ) ;
VkImageCopy copyRegion { } ;
copyRegion . srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 0 , 1 } ;
copyRegion . srcOffset = { 0 , 0 , 0 } ;
copyRegion . dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 0 , 1 } ;
copyRegion . dstOffset = { 0 , 0 , 0 } ;
copyRegion . extent = { width , height , 1 } ;
vkCmdCopyImage ( drawCmdBuffers [ i ] , storageImage . image , VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL , swapChain . images [ i ] , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , 1 , & copyRegion ) ;
// Transition swap chain image back for presentation
vks : : tools : : setImageLayout (
drawCmdBuffers [ i ] ,
swapChain . images [ i ] ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ,
subresourceRange ) ;
// Transition ray tracing output image back to general layout
vks : : tools : : setImageLayout (
drawCmdBuffers [ i ] ,
storageImage . image ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ,
VK_IMAGE_LAYOUT_GENERAL ,
subresourceRange ) ;
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
}
}
void updateUniformBuffers ( )
{
uniformData . projInverse = glm : : inverse ( camera . matrices . perspective ) ;
uniformData . viewInverse = glm : : inverse ( camera . matrices . view ) ;
memcpy ( ubo . mapped , & uniformData , sizeof ( uniformData ) ) ;
}
void getEnabledFeatures ( )
{
// Enable features required for ray tracing using feature chaining via pNext
enabledBufferDeviceAddresFeatures . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES ;
enabledBufferDeviceAddresFeatures . bufferDeviceAddress = VK_TRUE ;
enabledRayTracingPipelineFeatures . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR ;
enabledRayTracingPipelineFeatures . rayTracingPipeline = VK_TRUE ;
enabledRayTracingPipelineFeatures . pNext = & enabledBufferDeviceAddresFeatures ;
enabledAccelerationStructureFeatures . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR ;
enabledAccelerationStructureFeatures . accelerationStructure = VK_TRUE ;
enabledAccelerationStructureFeatures . pNext = & enabledRayTracingPipelineFeatures ;
deviceCreatepNextChain = & enabledAccelerationStructureFeatures ;
}
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
// Get ray tracing pipeline properties, which will be used later on in the sample
rayTracingPipelineProperties . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR ;
VkPhysicalDeviceProperties2 deviceProperties2 { } ;
deviceProperties2 . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 ;
deviceProperties2 . pNext = & rayTracingPipelineProperties ;
vkGetPhysicalDeviceProperties2 ( physicalDevice , & deviceProperties2 ) ;
// Get acceleration structure properties, which will be used later on in the sample
accelerationStructureFeatures . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR ;
VkPhysicalDeviceFeatures2 deviceFeatures2 { } ;
deviceFeatures2 . sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ;
deviceFeatures2 . pNext = & accelerationStructureFeatures ;
vkGetPhysicalDeviceFeatures2 ( physicalDevice , & deviceFeatures2 ) ;
// Get the ray tracing and accelertion structure related function pointers required by this sample
vkGetBufferDeviceAddressKHR = reinterpret_cast < PFN_vkGetBufferDeviceAddressKHR > ( vkGetDeviceProcAddr ( device , " vkGetBufferDeviceAddressKHR " ) ) ;
vkCmdBuildAccelerationStructuresKHR = reinterpret_cast < PFN_vkCmdBuildAccelerationStructuresKHR > ( vkGetDeviceProcAddr ( device , " vkCmdBuildAccelerationStructuresKHR " ) ) ;
vkBuildAccelerationStructuresKHR = reinterpret_cast < PFN_vkBuildAccelerationStructuresKHR > ( vkGetDeviceProcAddr ( device , " vkBuildAccelerationStructuresKHR " ) ) ;
vkCreateAccelerationStructureKHR = reinterpret_cast < PFN_vkCreateAccelerationStructureKHR > ( vkGetDeviceProcAddr ( device , " vkCreateAccelerationStructureKHR " ) ) ;
vkDestroyAccelerationStructureKHR = reinterpret_cast < PFN_vkDestroyAccelerationStructureKHR > ( vkGetDeviceProcAddr ( device , " vkDestroyAccelerationStructureKHR " ) ) ;
vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast < PFN_vkGetAccelerationStructureBuildSizesKHR > ( vkGetDeviceProcAddr ( device , " vkGetAccelerationStructureBuildSizesKHR " ) ) ;
vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast < PFN_vkGetAccelerationStructureDeviceAddressKHR > ( vkGetDeviceProcAddr ( device , " vkGetAccelerationStructureDeviceAddressKHR " ) ) ;
vkCmdTraceRaysKHR = reinterpret_cast < PFN_vkCmdTraceRaysKHR > ( vkGetDeviceProcAddr ( device , " vkCmdTraceRaysKHR " ) ) ;
vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast < PFN_vkGetRayTracingShaderGroupHandlesKHR > ( vkGetDeviceProcAddr ( device , " vkGetRayTracingShaderGroupHandlesKHR " ) ) ;
vkCreateRayTracingPipelinesKHR = reinterpret_cast < PFN_vkCreateRayTracingPipelinesKHR > ( vkGetDeviceProcAddr ( device , " vkCreateRayTracingPipelinesKHR " ) ) ;
// Create the acceleration structures used to render the ray traced scene
createBottomLevelAccelerationStructure ( ) ;
createTopLevelAccelerationStructure ( ) ;
createStorageImage ( ) ;
createUniformBuffer ( ) ;
createRayTracingPipeline ( ) ;
createShaderBindingTable ( ) ;
createDescriptorSets ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
void draw ( )
{
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
if ( camera . updated )
updateUniformBuffers ( ) ;
}
} ;
VULKAN_EXAMPLE_MAIN ( )