diff --git a/base/VulkanInitializers.hpp b/base/VulkanInitializers.hpp index 6ae53302..795b5f9a 100644 --- a/base/VulkanInitializers.hpp +++ b/base/VulkanInitializers.hpp @@ -612,5 +612,48 @@ namespace vks return specializationInfo; } + // Ray tracing related + inline VkAccelerationStructureGeometryKHR accelerationStructureGeometryKHR() + { + VkAccelerationStructureGeometryKHR accelerationStructureGeometryKHR{}; + accelerationStructureGeometryKHR.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + return accelerationStructureGeometryKHR; + } + + inline VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfoKHR() + { + VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfoKHR{}; + accelerationStructureBuildGeometryInfoKHR.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + return accelerationStructureBuildGeometryInfoKHR; + } + + inline VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfoKHR() + { + VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfoKHR{}; + accelerationStructureBuildSizesInfoKHR.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + return accelerationStructureBuildSizesInfoKHR; + } + + inline VkRayTracingShaderGroupCreateInfoKHR rayTracingShaderGroupCreateInfoKHR() + { + VkRayTracingShaderGroupCreateInfoKHR rayTracingShaderGroupCreateInfoKHR{}; + rayTracingShaderGroupCreateInfoKHR.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + return rayTracingShaderGroupCreateInfoKHR; + } + + inline VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCreateInfoKHR() + { + VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCreateInfoKHR{}; + rayTracingPipelineCreateInfoKHR.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + return rayTracingPipelineCreateInfoKHR; + } + + inline VkWriteDescriptorSetAccelerationStructureKHR writeDescriptorSetAccelerationStructureKHR() + { + VkWriteDescriptorSetAccelerationStructureKHR writeDescriptorSetAccelerationStructureKHR{}; + writeDescriptorSetAccelerationStructureKHR.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + return writeDescriptorSetAccelerationStructureKHR; + } + } } \ No newline at end of file diff --git a/base/VulkanRaytracingSample.cpp b/base/VulkanRaytracingSample.cpp new file mode 100644 index 00000000..bea1e67a --- /dev/null +++ b/base/VulkanRaytracingSample.cpp @@ -0,0 +1,227 @@ +/* +* Extended sample base class for ray tracing based samples +* +* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#pragma once + +#include "VulkanRaytracingSample.h" + +void VulkanRaytracingSample::enableExtensions() +{ + // 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); +} + +VulkanRaytracingSample::ScratchBuffer VulkanRaytracingSample::createScratchBuffer(VkDeviceSize size) +{ + ScratchBuffer scratchBuffer{}; + // Buffer and memory + 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(vulkanDevice->logicalDevice, &bufferCreateInfo, nullptr, &scratchBuffer.handle)); + VkMemoryRequirements memoryRequirements{}; + vkGetBufferMemoryRequirements(vulkanDevice->logicalDevice, 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(vulkanDevice->logicalDevice, &memoryAllocateInfo, nullptr, &scratchBuffer.memory)); + VK_CHECK_RESULT(vkBindBufferMemory(vulkanDevice->logicalDevice, scratchBuffer.handle, scratchBuffer.memory, 0)); + // Buffer device address + VkBufferDeviceAddressInfoKHR bufferDeviceAddresInfo{}; + bufferDeviceAddresInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + bufferDeviceAddresInfo.buffer = scratchBuffer.handle; + scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(vulkanDevice->logicalDevice, &bufferDeviceAddresInfo); + return scratchBuffer; +} + +void VulkanRaytracingSample::deleteScratchBuffer(ScratchBuffer& scratchBuffer) +{ + if (scratchBuffer.memory != VK_NULL_HANDLE) { + vkFreeMemory(vulkanDevice->logicalDevice, scratchBuffer.memory, nullptr); + } + if (scratchBuffer.handle != VK_NULL_HANDLE) { + vkDestroyBuffer(vulkanDevice->logicalDevice, scratchBuffer.handle, nullptr); + } +} + +void VulkanRaytracingSample::createAccelerationStructure(AccelerationStructure& accelerationStructure, VkAccelerationStructureTypeKHR type, VkAccelerationStructureBuildSizesInfoKHR buildSizeInfo) +{ + // Buffer and memory + 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(vulkanDevice->logicalDevice, &bufferCreateInfo, nullptr, &accelerationStructure.buffer)); + VkMemoryRequirements memoryRequirements{}; + vkGetBufferMemoryRequirements(vulkanDevice->logicalDevice, 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(vulkanDevice->logicalDevice, &memoryAllocateInfo, nullptr, &accelerationStructure.memory)); + VK_CHECK_RESULT(vkBindBufferMemory(vulkanDevice->logicalDevice, accelerationStructure.buffer, accelerationStructure.memory, 0)); + // Acceleration structure + VkAccelerationStructureCreateInfoKHR accelerationStructureCreate_info{}; + accelerationStructureCreate_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; + accelerationStructureCreate_info.buffer = accelerationStructure.buffer; + accelerationStructureCreate_info.size = buildSizeInfo.accelerationStructureSize; + accelerationStructureCreate_info.type = type; + vkCreateAccelerationStructureKHR(vulkanDevice->logicalDevice, &accelerationStructureCreate_info, nullptr, &accelerationStructure.handle); + // AS device address + VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{}; + accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; + accelerationDeviceAddressInfo.accelerationStructure = accelerationStructure.handle; + accelerationStructure.deviceAddress = vkGetAccelerationStructureDeviceAddressKHR(vulkanDevice->logicalDevice, &accelerationDeviceAddressInfo); +} + +void VulkanRaytracingSample::deleteAccelerationStructure(AccelerationStructure& accelerationStructure) +{ + vkFreeMemory(device, accelerationStructure.memory, nullptr); + vkDestroyBuffer(device, accelerationStructure.buffer, nullptr); + vkDestroyAccelerationStructureKHR(device, accelerationStructure.handle, nullptr); +} + +uint64_t VulkanRaytracingSample::getBufferDeviceAddress(VkBuffer buffer) +{ + VkBufferDeviceAddressInfoKHR bufferDeviceAI{}; + bufferDeviceAI.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + bufferDeviceAI.buffer = buffer; + return vkGetBufferDeviceAddressKHR(vulkanDevice->logicalDevice, &bufferDeviceAI); +} + +void VulkanRaytracingSample::createStorageImage(VkFormat format, VkExtent3D extent) +{ + // Release ressources if image is to be recreated + if (storageImage.image != VK_NULL_HANDLE) { + vkDestroyImageView(device, storageImage.view, nullptr); + vkDestroyImage(device, storageImage.image, nullptr); + vkFreeMemory(device, storageImage.memory, nullptr); + storageImage = {}; + } + + VkImageCreateInfo image = vks::initializers::imageCreateInfo(); + image.imageType = VK_IMAGE_TYPE_2D; + image.format = format; + image.extent = extent; + 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(vulkanDevice->logicalDevice, &image, nullptr, &storageImage.image)); + + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(vulkanDevice->logicalDevice, 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(vulkanDevice->logicalDevice, &memoryAllocateInfo, nullptr, &storageImage.memory)); + VK_CHECK_RESULT(vkBindImageMemory(vulkanDevice->logicalDevice, storageImage.image, storageImage.memory, 0)); + + VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo(); + colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; + colorImageView.format = format; + 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(vulkanDevice->logicalDevice, &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); +} + +void VulkanRaytracingSample::deleteStorageImage() +{ + vkDestroyImageView(vulkanDevice->logicalDevice, storageImage.view, nullptr); + vkDestroyImage(vulkanDevice->logicalDevice, storageImage.image, nullptr); + vkFreeMemory(vulkanDevice->logicalDevice, storageImage.memory, nullptr); +} + +void VulkanRaytracingSample::prepare() +{ + VulkanExampleBase::prepare(); + // Get properties and features + 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); + 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 function pointers required for ray tracing + vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR")); + vkCmdBuildAccelerationStructuresKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR")); + vkBuildAccelerationStructuresKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR")); + vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR")); + vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR")); + vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR")); + vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR")); + vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR")); + vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR")); + vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR")); +} + +VkStridedDeviceAddressRegionKHR VulkanRaytracingSample::getSbtEntryStridedDeviceAddressRegion(VkBuffer buffer, uint32_t handleCount) +{ + VkStridedDeviceAddressRegionKHR stridedDeviceAddressRegionKHR{}; + stridedDeviceAddressRegionKHR.deviceAddress = getBufferDeviceAddress(buffer); + stridedDeviceAddressRegionKHR.stride = rayTracingPipelineProperties.shaderGroupHandleSize; + stridedDeviceAddressRegionKHR.size = rayTracingPipelineProperties.shaderGroupHandleSize * handleCount; + return stridedDeviceAddressRegionKHR; +} + +void VulkanRaytracingSample::createShaderBindingTable(ShaderBindingTable& shaderBindingTable, uint32_t handleCount) +{ + // Create buffer to hold all shader handles for the SBT + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &shaderBindingTable, + rayTracingPipelineProperties.shaderGroupHandleSize * handleCount)); + // Get the strided address to be used when dispatching the rays + shaderBindingTable.stridedDeviceAddressRegion = getSbtEntryStridedDeviceAddressRegion(shaderBindingTable.buffer, handleCount); + // Map persistent + shaderBindingTable.map(); +} diff --git a/base/VulkanRaytracingSample.h b/base/VulkanRaytracingSample.h new file mode 100644 index 00000000..cc4dedf7 --- /dev/null +++ b/base/VulkanRaytracingSample.h @@ -0,0 +1,82 @@ +/* +* Extended sample base class for ray tracing based samples +* +* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#pragma once + +#include "vulkan/vulkan.h" +#include "vulkanexamplebase.h" +#include "VulkanTools.h" +#include "VulkanDevice.h" + +class VulkanRaytracingSample : public VulkanExampleBase +{ +public: + // Function pointers for ray tracing related stuff + PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; + PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; + PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; + PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; + PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; + PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; + PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; + PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; + PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; + + // Available features and properties + VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties{}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures{}; + + // Enabled features and properties + VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{}; + VkPhysicalDeviceRayTracingPipelineFeaturesKHR enabledRayTracingPipelineFeatures{}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR enabledAccelerationStructureFeatures{}; + + // Holds information for a ray tracing scratch buffer that is used as a temporary storage + struct ScratchBuffer + { + uint64_t deviceAddress = 0; + VkBuffer handle = VK_NULL_HANDLE; + VkDeviceMemory memory = VK_NULL_HANDLE; + }; + + // Holds information for a ray tracing tracing acceleration structure + struct AccelerationStructure { + VkAccelerationStructureKHR handle; + uint64_t deviceAddress = 0; + VkDeviceMemory memory; + VkBuffer buffer; + }; + + // Holds information for a storage image that the ray tracing shaders output to + struct StorageImage { + VkDeviceMemory memory = VK_NULL_HANDLE; + VkImage image = VK_NULL_HANDLE; + VkImageView view = VK_NULL_HANDLE; + VkFormat format; + } storageImage; + + // Extends the buffer class and holds information for a shader binding table + class ShaderBindingTable : public vks::Buffer { + public: + VkStridedDeviceAddressRegionKHR stridedDeviceAddressRegion{}; + }; + + void enableExtensions(); + ScratchBuffer createScratchBuffer(VkDeviceSize size); + void deleteScratchBuffer(ScratchBuffer& scratchBuffer); + void createAccelerationStructure(AccelerationStructure& accelerationStructure, VkAccelerationStructureTypeKHR type, VkAccelerationStructureBuildSizesInfoKHR buildSizeInfo); + void deleteAccelerationStructure(AccelerationStructure& accelerationStructure); + uint64_t getBufferDeviceAddress(VkBuffer buffer); + void createStorageImage(VkFormat format, VkExtent3D extent); + void deleteStorageImage(); + VkStridedDeviceAddressRegionKHR getSbtEntryStridedDeviceAddressRegion(VkBuffer buffer, uint32_t handleCount); + void createShaderBindingTable(ShaderBindingTable& shaderBindingTable, uint32_t handleCount); + + virtual void prepare(); +}; diff --git a/data/shaders/glsl/raytracingbasic/closesthit.rchit.spv b/data/shaders/glsl/raytracingbasic/closesthit.rchit.spv index bbf4ba93..dd8cfc08 100644 Binary files a/data/shaders/glsl/raytracingbasic/closesthit.rchit.spv and b/data/shaders/glsl/raytracingbasic/closesthit.rchit.spv differ diff --git a/data/shaders/glsl/raytracingbasic/miss.rmiss.spv b/data/shaders/glsl/raytracingbasic/miss.rmiss.spv index 7fb66cdf..58fb3309 100644 Binary files a/data/shaders/glsl/raytracingbasic/miss.rmiss.spv and b/data/shaders/glsl/raytracingbasic/miss.rmiss.spv differ diff --git a/data/shaders/glsl/raytracingbasic/raygen.rgen.spv b/data/shaders/glsl/raytracingbasic/raygen.rgen.spv index 5cc908e5..ce9413a9 100644 Binary files a/data/shaders/glsl/raytracingbasic/raygen.rgen.spv and b/data/shaders/glsl/raytracingbasic/raygen.rgen.spv differ diff --git a/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv b/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv index 41dde2ca..148540f3 100644 Binary files a/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv and b/data/shaders/glsl/raytracingreflections/closesthit.rchit.spv differ diff --git a/data/shaders/glsl/raytracingreflections/miss.rmiss.spv b/data/shaders/glsl/raytracingreflections/miss.rmiss.spv index 2d3d0e3b..c168cc39 100644 Binary files a/data/shaders/glsl/raytracingreflections/miss.rmiss.spv and b/data/shaders/glsl/raytracingreflections/miss.rmiss.spv differ diff --git a/data/shaders/glsl/raytracingreflections/raygen.rgen.spv b/data/shaders/glsl/raytracingreflections/raygen.rgen.spv index aab87a9b..7e2b2d3c 100644 Binary files a/data/shaders/glsl/raytracingreflections/raygen.rgen.spv and b/data/shaders/glsl/raytracingreflections/raygen.rgen.spv differ diff --git a/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv b/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv index 1904fdde..486571c5 100644 Binary files a/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv and b/data/shaders/glsl/raytracingshadows/closesthit.rchit.spv differ diff --git a/data/shaders/glsl/raytracingshadows/miss.rmiss.spv b/data/shaders/glsl/raytracingshadows/miss.rmiss.spv index 7fb66cdf..58fb3309 100644 Binary files a/data/shaders/glsl/raytracingshadows/miss.rmiss.spv and b/data/shaders/glsl/raytracingshadows/miss.rmiss.spv differ diff --git a/data/shaders/glsl/raytracingshadows/raygen.rgen.spv b/data/shaders/glsl/raytracingshadows/raygen.rgen.spv index 53552e71..30ab96d6 100644 Binary files a/data/shaders/glsl/raytracingshadows/raygen.rgen.spv and b/data/shaders/glsl/raytracingshadows/raygen.rgen.spv differ diff --git a/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv b/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv index cf13a98a..65b01ba9 100644 Binary files a/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv and b/data/shaders/glsl/raytracingshadows/shadow.rmiss.spv differ diff --git a/examples/raytracingbasic/raytracingbasic.cpp b/examples/raytracingbasic/raytracingbasic.cpp index 3cbbe667..aa7c6397 100644 --- a/examples/raytracingbasic/raytracingbasic.cpp +++ b/examples/raytracingbasic/raytracingbasic.cpp @@ -1,71 +1,61 @@ /* -* Vulkan Example - Basic hardware accelerated ray tracing example using VK_KHR_ray_traying +* Vulkan Example - Basic hardware accelerated ray tracing example * * Copyright (C) 2019-2020 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ -#define VK_ENABLE_BETA_EXTENSIONS - #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 buffer = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; -}; - -// Holds data for a memory object bound to an acceleration structure -struct RayTracingObjectMemory -{ - uint64_t deviceAddress = 0; + VkBuffer handle = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE; }; // Ray tracing acceleration structure struct AccelerationStructure { - VkAccelerationStructureKHR accelerationStructure; - uint64_t handle; - RayTracingObjectMemory objectMemory; + VkAccelerationStructureKHR handle; + uint64_t deviceAddress = 0; + VkDeviceMemory memory; + VkBuffer buffer; }; -// Indices for the different ray tracing shader types used in this example -#define INDEX_RAYGEN_GROUP 0 -#define INDEX_MISS_GROUP 1 -#define INDEX_CLOSEST_HIT_GROUP 2 - class VulkanExample : public VulkanExampleBase { public: PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; - PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR; PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; - PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR; - PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR; - PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR; + PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; + PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; + PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR; PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; - VkPhysicalDeviceRayTracingPropertiesKHR rayTracingProperties{}; - VkPhysicalDeviceRayTracingFeaturesKHR rayTracingFeatures{}; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties{}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures{}; VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{}; - VkPhysicalDeviceRayTracingFeaturesKHR enabledRayTracingFeatures{}; + VkPhysicalDeviceRayTracingPipelineFeaturesKHR enabledRayTracingPipelineFeatures{}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR enabledAccelerationStructureFeatures{}; - AccelerationStructure bottomLevelAS; - AccelerationStructure topLevelAS; + AccelerationStructure bottomLevelAS{}; + AccelerationStructure topLevelAS{}; vks::Buffer vertexBuffer; vks::Buffer indexBuffer; uint32_t indexCount; + vks::Buffer transformBuffer; std::vector shaderGroups{}; - vks::Buffer shaderBindingTable; + vks::Buffer raygenShaderBindingTable; + vks::Buffer missShaderBindingTable; + vks::Buffer hitShaderBindingTable; struct StorageImage { VkDeviceMemory memory; @@ -88,22 +78,29 @@ public: VulkanExample() : VulkanExampleBase() { title = "Ray tracing basic"; - settings.overlay = true; + 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)); - // Enable instance and device extensions required to use VK_KHR_ray_tracing - enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME); + + // 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); - enabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); - // We require Vulkan 1.2 for ray tracing - apiVersion = VK_API_VERSION_1_2; + + // 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() @@ -114,59 +111,53 @@ public: vkDestroyImageView(device, storageImage.view, nullptr); vkDestroyImage(device, storageImage.image, nullptr); vkFreeMemory(device, storageImage.memory, nullptr); - vkDestroyAccelerationStructureKHR(device, bottomLevelAS.accelerationStructure, nullptr); - vkDestroyAccelerationStructureKHR(device, topLevelAS.accelerationStructure, 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(); - shaderBindingTable.destroy(); + transformBuffer.destroy(); + raygenShaderBindingTable.destroy(); + missShaderBindingTable.destroy(); + hitShaderBindingTable.destroy(); ubo.destroy(); - deleteObjectMemory(bottomLevelAS.objectMemory); - deleteObjectMemory(topLevelAS.objectMemory); } /* Create a scratch buffer to hold temporary data for a ray tracing acceleration structure */ - RayTracingScratchBuffer createScratchBuffer(VkAccelerationStructureKHR accelerationStructure) + RayTracingScratchBuffer createScratchBuffer(VkDeviceSize size) { RayTracingScratchBuffer scratchBuffer{}; - VkMemoryRequirements2 memoryRequirements2{}; - memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - - VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{}; - accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR; - accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - accelerationStructureMemoryRequirements.accelerationStructure = accelerationStructure; - vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2); - - VkBufferCreateInfo bufferCI{}; - bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCI.size = memoryRequirements2.memoryRequirements.size; - bufferCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCI, nullptr, &scratchBuffer.buffer)); + 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.buffer, &memoryRequirements); + vkGetBufferMemoryRequirements(device, scratchBuffer.handle, &memoryRequirements); - VkMemoryAllocateFlagsInfo memoryAllocateFI{}; - memoryAllocateFI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - memoryAllocateFI.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{}; + memoryAllocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + memoryAllocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.pNext = &memoryAllocateFI; - memoryAI.allocationSize = memoryRequirements.size; - memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &scratchBuffer.memory)); - VK_CHECK_RESULT(vkBindBufferMemory(device, scratchBuffer.buffer, scratchBuffer.memory, 0)); + 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 buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = scratchBuffer.buffer; - scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &buffer_device_address_info); + VkBufferDeviceAddressInfoKHR bufferDeviceAddressInfo{}; + bufferDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + bufferDeviceAddressInfo.buffer = scratchBuffer.handle; + scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &bufferDeviceAddressInfo); return scratchBuffer; } @@ -176,45 +167,32 @@ public: if (scratchBuffer.memory != VK_NULL_HANDLE) { vkFreeMemory(device, scratchBuffer.memory, nullptr); } - if (scratchBuffer.buffer != VK_NULL_HANDLE) { - vkDestroyBuffer(device, scratchBuffer.buffer, nullptr); + if (scratchBuffer.handle != VK_NULL_HANDLE) { + vkDestroyBuffer(device, scratchBuffer.handle, nullptr); } } - /* - Allocate memory that will be attached to a ray tracing acceleration structure - */ - RayTracingObjectMemory createObjectMemory(VkAccelerationStructureKHR acceleration_structure) + void createAccelerationStructureBuffer(AccelerationStructure &accelerationStructure, VkAccelerationStructureBuildSizesInfoKHR buildSizeInfo) { - RayTracingObjectMemory objectMemory{}; - - VkMemoryRequirements2 memoryRequirements2{}; - memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - - VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{}; - accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR; - accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - accelerationStructureMemoryRequirements.accelerationStructure = acceleration_structure; - vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2); - - VkMemoryRequirements memoryRequirements = memoryRequirements2.memoryRequirements; - - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.allocationSize = memoryRequirements.size; - memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &objectMemory.memory)); - - return objectMemory; + 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)); } - void deleteObjectMemory(RayTracingObjectMemory& objectMemory) - { - if (objectMemory.memory != VK_NULL_HANDLE) { - vkFreeMemory(device, objectMemory.memory, nullptr); - } - } /* Gets the device address from a buffer that's required for some of the buffers used for ray tracing @@ -293,109 +271,134 @@ public: std::vector indices = { 0, 1, 2 }; indexCount = static_cast(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_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + 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_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + 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); - VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{}; - accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; - accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - accelerationCreateGeometryInfo.maxPrimitiveCount = 1; - accelerationCreateGeometryInfo.indexType = VK_INDEX_TYPE_UINT32; - accelerationCreateGeometryInfo.maxVertexCount = static_cast(vertices.size()); - accelerationCreateGeometryInfo.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; - accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE; - - VkAccelerationStructureCreateInfoKHR accelerationCI{}; - accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationCI.maxGeometryCount = 1; - accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo; - VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &bottomLevelAS.accelerationStructure)); - - // Bind object memory to the top level acceleration structure - bottomLevelAS.objectMemory = createObjectMemory(bottomLevelAS.accelerationStructure); - - VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{}; - bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - bindAccelerationMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure; - bindAccelerationMemoryInfo.memory = bottomLevelAS.objectMemory.memory; - VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo)); - + // 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.deviceAddress = vertexBufferDeviceAddress.deviceAddress; + 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.deviceAddress = indexBufferDeviceAddress.deviceAddress; + 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); - std::vector acceleration_geometries = { accelerationStructureGeometry }; - VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data(); + 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(bottomLevelAS.accelerationStructure); + 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.update = VK_FALSE; - accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.accelerationStructure; - accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE; + accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.handle; accelerationBuildGeometryInfo.geometryCount = 1; - accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries; + accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry; accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress; - VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{}; - accelerationBuildOffsetInfo.primitiveCount = 1; - accelerationBuildOffsetInfo.primitiveOffset = 0x0; - accelerationBuildOffsetInfo.firstVertex = 0; - accelerationBuildOffsetInfo.transformOffset = 0x0; + VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{}; + accelerationStructureBuildRangeInfo.primitiveCount = numTriangles; + accelerationStructureBuildRangeInfo.primitiveOffset = 0; + accelerationStructureBuildRangeInfo.firstVertex = 0; + accelerationStructureBuildRangeInfo.transformOffset = 0; + std::vector accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo }; - std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo }; - - if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands) + if (accelerationStructureFeatures.accelerationStructureHostCommands) { // Implementation supports building acceleration structure building on host - VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data())); + vkBuildAccelerationStructuresKHR( + device, + VK_NULL_HANDLE, + 1, + &accelerationBuildGeometryInfo, + accelerationBuildStructureRangeInfos.data()); } else { // Acceleration structure needs to be build on the device VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()); + 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.accelerationStructure; - - bottomLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); + accelerationDeviceAddressInfo.accelerationStructure = bottomLevelAS.handle; + bottomLevelAS.deviceAddress = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); deleteScratchBuffer(scratchBuffer); } @@ -405,132 +408,157 @@ public: */ void createTopLevelAccelerationStructure() { - VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{}; - accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; - accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - accelerationCreateGeometryInfo.maxPrimitiveCount = 1; - accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE; - - VkAccelerationStructureCreateInfoKHR accelerationCI{}; - accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationCI.maxGeometryCount = 1; - accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo; - VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &topLevelAS.accelerationStructure)); - - // Bind object memory to the top level acceleration structure - topLevelAS.objectMemory = createObjectMemory(topLevelAS.accelerationStructure); - - VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{}; - bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - bindAccelerationMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure; - bindAccelerationMemoryInfo.memory = topLevelAS.objectMemory.memory; - VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo)); - - VkTransformMatrixKHR 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 }; VkAccelerationStructureInstanceKHR instance{}; - instance.transform = transform_matrix; + 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.handle; + 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_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(instance), + sizeof(VkAccelerationStructureInstanceKHR), &instance)); - VkDeviceOrHostAddressConstKHR instance_data_device_address{}; - instance_data_device_address.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer); + VkDeviceOrHostAddressConstKHR instanceDataDeviceAddress{}; + instanceDataDeviceAddress.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer); VkAccelerationStructureGeometryKHR accelerationStructureGeometry{}; accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_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.deviceAddress = instance_data_device_address.deviceAddress; + accelerationStructureGeometry.geometry.instances.data = instanceDataDeviceAddress; - std::vector acceleration_geometries = { accelerationStructureGeometry }; - VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data(); + // 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(topLevelAS.accelerationStructure); + 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.update = VK_FALSE; - accelerationBuildGeometryInfo.srcAccelerationStructure = VK_NULL_HANDLE; - accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.accelerationStructure; - accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE; + accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.handle; accelerationBuildGeometryInfo.geometryCount = 1; - accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries; + accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry; accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress; - VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{}; - accelerationBuildOffsetInfo.primitiveCount = 1; - accelerationBuildOffsetInfo.primitiveOffset = 0x0; - accelerationBuildOffsetInfo.firstVertex = 0; - accelerationBuildOffsetInfo.transformOffset = 0x0; - std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo }; + VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{}; + accelerationStructureBuildRangeInfo.primitiveCount = 1; + accelerationStructureBuildRangeInfo.primitiveOffset = 0; + accelerationStructureBuildRangeInfo.firstVertex = 0; + accelerationStructureBuildRangeInfo.transformOffset = 0; + std::vector accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo }; - if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands) + if (accelerationStructureFeatures.accelerationStructureHostCommands) { // Implementation supports building acceleration structure building on host - VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data())); + vkBuildAccelerationStructuresKHR( + device, + VK_NULL_HANDLE, + 1, + &accelerationBuildGeometryInfo, + accelerationBuildStructureRangeInfos.data()); } else { // Acceleration structure needs to be build on the device VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()); + 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.accelerationStructure; - - topLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); + accelerationDeviceAddressInfo.accelerationStructure = topLevelAS.handle; + topLevelAS.deviceAddress = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); deleteScratchBuffer(scratchBuffer); instancesBuffer.destroy(); } /* - Create the Shader Binding Table that binds the programs and top-level acceleration structure + 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 handleAlignment = rayTracingPipelineProperties.shaderGroupHandleAlignment; const uint32_t groupCount = static_cast(shaderGroups.size()); + const uint32_t sbtSize = handleSize * groupCount; - const uint32_t sbtSize = rayTracingProperties.shaderGroupBaseAlignment * groupCount; - VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &shaderBindingTable, sbtSize)); - shaderBindingTable.map(); - - // Write the shader handles to the shader binding table std::vector shaderHandleStorage(sbtSize); VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data())); - auto* data = static_cast(shaderBindingTable.mapped); - // This part is required, as the alignment and handle size may differ - for (uint32_t i = 0; i < groupCount; i++) - { - memcpy(data, shaderHandleStorage.data() + i * rayTracingProperties.shaderGroupHandleSize, rayTracingProperties.shaderGroupHandleSize); - data += rayTracingProperties.shaderGroupBaseAlignment; - } - shaderBindingTable.unmap(); + 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)); + VK_CHECK_RESULT(vulkanDevice->createBuffer(bufferUsageFlags, memoryUsageFlags, &missShaderBindingTable, handleSize)); + VK_CHECK_RESULT(vulkanDevice->createBuffer(bufferUsageFlags, memoryUsageFlags, &hitShaderBindingTable, handleSize)); + + // Copy handles + raygenShaderBindingTable.map(); + missShaderBindingTable.map(); + hitShaderBindingTable.map(); + memcpy(raygenShaderBindingTable.mapped, shaderHandleStorage.data(), handleSize); + memcpy(missShaderBindingTable.mapped, shaderHandleStorage.data() + handleAlignment, handleSize); + memcpy(hitShaderBindingTable.mapped, shaderHandleStorage.data() + handleAlignment * 2, handleSize); } /* @@ -552,7 +580,7 @@ public: VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo{}; descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; descriptorAccelerationStructureInfo.accelerationStructureCount = 1; - descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure; + descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.handle; VkWriteDescriptorSet accelerationStructureWrite{}; accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -619,55 +647,62 @@ public: pipelineLayoutCI.pSetLayouts = &descriptorSetLayout; VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); - const uint32_t shaderIndexRaygen = 0; - const uint32_t shaderIndexMiss = 1; - const uint32_t shaderIndexClosestHit = 2; - - std::array shaderStages; - shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "raytracingbasic/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR); - shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "raytracingbasic/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR); - shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "raytracingbasic/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - /* Setup ray tracing shader groups */ - VkRayTracingShaderGroupCreateInfoKHR raygenGroupCI{}; - raygenGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - raygenGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - raygenGroupCI.generalShader = shaderIndexRaygen; - raygenGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR; - raygenGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - raygenGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(raygenGroupCI); + std::vector shaderStages; - VkRayTracingShaderGroupCreateInfoKHR missGroupCI{}; - missGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - missGroupCI.generalShader = shaderIndexMiss; - missGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR; - missGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - missGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(missGroupCI); + // Ray generation group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingbasic/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(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); + } - VkRayTracingShaderGroupCreateInfoKHR closesHitGroupCI{}; - closesHitGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - closesHitGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - closesHitGroupCI.generalShader = VK_SHADER_UNUSED_KHR; - closesHitGroupCI.closestHitShader = shaderIndexClosestHit; - closesHitGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - closesHitGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(closesHitGroupCI); + // Miss group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingbasic/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(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() + "raytracingbasic/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(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(shaderStages.size()); rayTracingPipelineCI.pStages = shaderStages.data(); rayTracingPipelineCI.groupCount = static_cast(shaderGroups.size()); rayTracingPipelineCI.pGroups = shaderGroups.data(); - rayTracingPipelineCI.maxRecursionDepth = 1; + rayTracingPipelineCI.maxPipelineRayRecursionDepth = 1; rayTracingPipelineCI.layout = pipelineLayout; - rayTracingPipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; - VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline)); + VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline)); } /* @@ -721,37 +756,26 @@ public: { VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); - /* - 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); - - /* Setup the buffer regions pointing to the shaders in our shader binding table */ - const VkDeviceSize sbtSize = rayTracingProperties.shaderGroupBaseAlignment * (VkDeviceSize)shaderGroups.size(); - VkStridedBufferRegionKHR raygenShaderSBTEntry{}; - raygenShaderSBTEntry.buffer = shaderBindingTable.buffer; - raygenShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_RAYGEN_GROUP); - raygenShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - raygenShaderSBTEntry.size = sbtSize; + VkStridedDeviceAddressRegionKHR raygenShaderSbtEntry{}; + raygenShaderSbtEntry.deviceAddress = getBufferDeviceAddress(raygenShaderBindingTable.buffer); + raygenShaderSbtEntry.stride = rayTracingPipelineProperties.shaderGroupHandleSize; + raygenShaderSbtEntry.size = rayTracingPipelineProperties.shaderGroupHandleSize; - VkStridedBufferRegionKHR missShaderSBTEntry{}; - missShaderSBTEntry.buffer = shaderBindingTable.buffer; - missShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_MISS_GROUP); - missShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - missShaderSBTEntry.size = sbtSize; + VkStridedDeviceAddressRegionKHR missShaderSbtEntry{}; + missShaderSbtEntry.deviceAddress = getBufferDeviceAddress(missShaderBindingTable.buffer); + missShaderSbtEntry.stride = rayTracingPipelineProperties.shaderGroupHandleSize; + missShaderSbtEntry.size = rayTracingPipelineProperties.shaderGroupHandleSize; - VkStridedBufferRegionKHR hitShaderSBTEntry{}; - hitShaderSBTEntry.buffer = shaderBindingTable.buffer; - hitShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_CLOSEST_HIT_GROUP); - hitShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - hitShaderSBTEntry.size = sbtSize; + VkStridedDeviceAddressRegionKHR hitShaderSbtEntry{}; + hitShaderSbtEntry.deviceAddress = getBufferDeviceAddress(hitShaderBindingTable.buffer); + hitShaderSbtEntry.stride = rayTracingPipelineProperties.shaderGroupHandleSize; + hitShaderSbtEntry.size = rayTracingPipelineProperties.shaderGroupHandleSize; - VkStridedBufferRegionKHR callableShaderSBTEntry{}; + VkStridedDeviceAddressRegionKHR callableShaderSbtEntry{}; /* Dispatch the ray tracing commands @@ -761,10 +785,10 @@ public: vkCmdTraceRaysKHR( drawCmdBuffers[i], - &raygenShaderSBTEntry, - &missShaderSBTEntry, - &hitShaderSBTEntry, - &callableShaderSBTEntry, + &raygenShaderSbtEntry, + &missShaderSbtEntry, + &hitShaderSbtEntry, + &callableShaderSbtEntry, width, height, 1); @@ -829,40 +853,43 @@ public: // 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; - - enabledRayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR; - enabledRayTracingFeatures.rayTracing = VK_TRUE; - enabledRayTracingFeatures.pNext = &enabledBufferDeviceAddresFeatures; - deviceCreatepNextChain = &enabledRayTracingFeatures; + 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(); - // Query the ray tracing properties of the current implementation, we will need them later on - rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR; - VkPhysicalDeviceProperties2 deviceProps2{}; - deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - deviceProps2.pNext = &rayTracingProperties; - vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2); + // 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); - // Query the ray tracing properties of the current implementation, we will need them later on - rayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR; + // 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 = &rayTracingFeatures; + deviceFeatures2.pNext = &accelerationStructureFeatures; vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2); - // Get the function pointers required for ray tracing + // Get the ray tracing and accelertion structure related function pointers required by this sample vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR")); - vkBindAccelerationStructureMemoryKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryKHR")); + vkCmdBuildAccelerationStructuresKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR")); + vkBuildAccelerationStructuresKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR")); vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR")); vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR")); - vkGetAccelerationStructureMemoryRequirementsKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsKHR")); - vkCmdBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureKHR")); - vkBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructureKHR")); + vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR")); vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR")); vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR")); vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR")); diff --git a/examples/raytracingreflections/raytracingreflections.cpp b/examples/raytracingreflections/raytracingreflections.cpp index 52efed8f..3e4a6eef 100644 --- a/examples/raytracingreflections/raytracingreflections.cpp +++ b/examples/raytracingreflections/raytracingreflections.cpp @@ -1,5 +1,5 @@ /* -* Vulkan Example - Hardware accelerated ray tracing example for doing reflections using VK_KHR_ray_traying +* Vulkan Example - Hardware accelerated ray tracing example for doing reflections * * Renders a complex scene doing recursion inside the shaders for creating reflections * @@ -8,69 +8,21 @@ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ -#define VK_ENABLE_BETA_EXTENSIONS - -#include "vulkanexamplebase.h" +#include "VulkanRaytracingSample.h" #include "VulkanglTFModel.h" -// Ray tracing utility structures, see ray tracing basic sample for details -struct RayTracingScratchBuffer -{ - uint64_t deviceAddress = 0; - VkBuffer buffer = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; -}; - -struct RayTracingObjectMemory -{ - uint64_t deviceAddress = 0; - VkDeviceMemory memory = VK_NULL_HANDLE; -}; - -struct AccelerationStructure { - VkAccelerationStructureKHR accelerationStructure; - uint64_t handle; - RayTracingObjectMemory objectMemory; -}; - -// Indices for the different ray tracing groups used in this example -#define INDEX_RAYGEN_GROUP 0 -#define INDEX_MISS_GROUP 1 -#define INDEX_CLOSEST_HIT_GROUP 2 - -class VulkanExample : public VulkanExampleBase +class VulkanExample : public VulkanRaytracingSample { public: - PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; - PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR; - PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; - PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; - PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR; - PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR; - PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR; - PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; - PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; - PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; - PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; - - VkPhysicalDeviceRayTracingPropertiesKHR rayTracingProperties{}; - VkPhysicalDeviceRayTracingFeaturesKHR rayTracingFeatures{}; - - VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{}; - VkPhysicalDeviceRayTracingFeaturesKHR enabledRayTracingFeatures{}; - - AccelerationStructure bottomLevelAS; - AccelerationStructure topLevelAS; + AccelerationStructure bottomLevelAS{}; + AccelerationStructure topLevelAS{}; std::vector shaderGroups{}; - vks::Buffer shaderBindingTable; - - struct StorageImage { - VkDeviceMemory memory; - VkImage image; - VkImageView view; - VkFormat format; - } storageImage; + struct ShaderBindingTables { + ShaderBindingTable raygen; + ShaderBindingTable miss; + ShaderBindingTable hit; + } shaderBindingTables; struct UniformData { glm::mat4 viewInverse; @@ -87,7 +39,8 @@ public: vkglTF::Model scene; - VulkanExample() : VulkanExampleBase() + // This sample is derived from an extended base class that saves most of the ray tracing setup boiler plate + VulkanExample() : VulkanRaytracingSample() { title = "Ray tracing reflections"; settings.overlay = false; @@ -97,17 +50,7 @@ public: 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.5f, -2.0f)); - // Enable instance and device extensions required to use VK_KHR_ray_tracing - enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME); - 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); - enabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); - // We require Vulkan 1.2 for ray tracing - apiVersion = VK_API_VERSION_1_2; + enableExtensions(); } ~VulkanExample() @@ -115,248 +58,107 @@ public: 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); - vkDestroyAccelerationStructureKHR(device, bottomLevelAS.accelerationStructure, nullptr); - vkDestroyAccelerationStructureKHR(device, topLevelAS.accelerationStructure, nullptr); - shaderBindingTable.destroy(); + deleteStorageImage(); + deleteAccelerationStructure(bottomLevelAS); + deleteAccelerationStructure(topLevelAS); + shaderBindingTables.raygen.destroy(); + shaderBindingTables.miss.destroy(); + shaderBindingTables.hit.destroy(); ubo.destroy(); - deleteObjectMemory(bottomLevelAS.objectMemory); - deleteObjectMemory(topLevelAS.objectMemory); } /* - Ray tracing utility functions, see ray tracing basic sample for details -*/ - RayTracingScratchBuffer createScratchBuffer(VkAccelerationStructureKHR accelerationStructure) - { - RayTracingScratchBuffer scratchBuffer{}; - VkMemoryRequirements2 memoryRequirements2{}; - memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{}; - accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR; - accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - accelerationStructureMemoryRequirements.accelerationStructure = accelerationStructure; - vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2); - VkBufferCreateInfo bufferCI{}; - bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCI.size = memoryRequirements2.memoryRequirements.size; - bufferCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCI, nullptr, &scratchBuffer.buffer)); - VkMemoryRequirements memoryRequirements{}; - vkGetBufferMemoryRequirements(device, scratchBuffer.buffer, &memoryRequirements); - VkMemoryAllocateFlagsInfo memoryAllocateFI{}; - memoryAllocateFI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - memoryAllocateFI.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.pNext = &memoryAllocateFI; - memoryAI.allocationSize = memoryRequirements.size; - memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &scratchBuffer.memory)); - VK_CHECK_RESULT(vkBindBufferMemory(device, scratchBuffer.buffer, scratchBuffer.memory, 0)); - VkBufferDeviceAddressInfoKHR buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = scratchBuffer.buffer; - scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &buffer_device_address_info); - return scratchBuffer; - } - - void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer) - { - if (scratchBuffer.memory != VK_NULL_HANDLE) { - vkFreeMemory(device, scratchBuffer.memory, nullptr); - } - if (scratchBuffer.buffer != VK_NULL_HANDLE) { - vkDestroyBuffer(device, scratchBuffer.buffer, nullptr); - } - } - - RayTracingObjectMemory createObjectMemory(VkAccelerationStructureKHR acceleration_structure) - { - RayTracingObjectMemory objectMemory{}; - VkMemoryRequirements2 memoryRequirements2{}; - memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{}; - accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR; - accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - accelerationStructureMemoryRequirements.accelerationStructure = acceleration_structure; - vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2); - VkMemoryRequirements memoryRequirements = memoryRequirements2.memoryRequirements; - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.allocationSize = memoryRequirements.size; - memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &objectMemory.memory)); - return objectMemory; - } - - void deleteObjectMemory(RayTracingObjectMemory& objectMemory) - { - if (objectMemory.memory != VK_NULL_HANDLE) { - vkFreeMemory(device, objectMemory.memory, nullptr); - } - } - - 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 + Create the bottom level acceleration structure contains the scene's actual geometry (vertices, triangles) */ - 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() { // Instead of a simple triangle, we'll be loading a more complex scene for this example // The shaders are accessing the vertex and index buffers of the scene, so the proper usage flag has to be set on the vertex and index buffers for the scene - vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY; scene.loadFromFile(getAssetPath() + "models/reflection_scene.gltf", vulkanDevice, queue, glTFLoadingFlags); - const uint32_t numTriangles = static_cast(scene.indices.count) / 3; - VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{}; VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{}; vertexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.vertices.buffer); indexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.indices.buffer); - VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{}; - accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; - accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - accelerationCreateGeometryInfo.maxPrimitiveCount = numTriangles; - accelerationCreateGeometryInfo.indexType = VK_INDEX_TYPE_UINT32; - accelerationCreateGeometryInfo.maxVertexCount = static_cast(scene.vertices.count); - accelerationCreateGeometryInfo.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; - accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE; + uint32_t numTriangles = static_cast(scene.indices.count) / 3; + uint32_t maxVertex = scene.vertices.count; - VkAccelerationStructureCreateInfoKHR accelerationCI{}; - accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationCI.maxGeometryCount = 1; - accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo; - VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &bottomLevelAS.accelerationStructure)); - - // Bind object memory to the top level acceleration structure - bottomLevelAS.objectMemory = createObjectMemory(bottomLevelAS.accelerationStructure); - - VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{}; - bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - bindAccelerationMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure; - bindAccelerationMemoryInfo.memory = bottomLevelAS.objectMemory.memory; - VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo)); - - VkAccelerationStructureGeometryKHR accelerationStructureGeometry{}; - accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + // Build + VkAccelerationStructureGeometryKHR accelerationStructureGeometry = vks::initializers::accelerationStructureGeometryKHR(); 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.deviceAddress = vertexBufferDeviceAddress.deviceAddress; + accelerationStructureGeometry.geometry.triangles.vertexData = vertexBufferDeviceAddress; + accelerationStructureGeometry.geometry.triangles.maxVertex = maxVertex; accelerationStructureGeometry.geometry.triangles.vertexStride = sizeof(vkglTF::Vertex); accelerationStructureGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; - accelerationStructureGeometry.geometry.triangles.indexData.deviceAddress = indexBufferDeviceAddress.deviceAddress; + accelerationStructureGeometry.geometry.triangles.indexData = indexBufferDeviceAddress; + accelerationStructureGeometry.geometry.triangles.transformData.deviceAddress = 0; + accelerationStructureGeometry.geometry.triangles.transformData.hostAddress = nullptr; - std::vector acceleration_geometries = { accelerationStructureGeometry }; - VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data(); + // Get size info + VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); + 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; + + VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo = vks::initializers::accelerationStructureBuildSizesInfoKHR(); + vkGetAccelerationStructureBuildSizesKHR( + device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &accelerationStructureBuildGeometryInfo, + &numTriangles, + &accelerationStructureBuildSizesInfo); + + createAccelerationStructure(bottomLevelAS, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, accelerationStructureBuildSizesInfo); // Create a small scratch buffer used during build of the bottom level acceleration structure - RayTracingScratchBuffer scratchBuffer = createScratchBuffer(bottomLevelAS.accelerationStructure); + ScratchBuffer scratchBuffer = createScratchBuffer(accelerationStructureBuildSizesInfo.buildScratchSize); - VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{}; - accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationBuildGeometryInfo.update = VK_FALSE; - accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.accelerationStructure; - accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE; + accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.handle; accelerationBuildGeometryInfo.geometryCount = 1; - accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries; + accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry; accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress; - VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{}; - accelerationBuildOffsetInfo.primitiveCount = numTriangles; - accelerationBuildOffsetInfo.primitiveOffset = 0x0; - accelerationBuildOffsetInfo.firstVertex = 0; - accelerationBuildOffsetInfo.transformOffset = 0x0; + VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{}; + accelerationStructureBuildRangeInfo.primitiveCount = numTriangles; + accelerationStructureBuildRangeInfo.primitiveOffset = 0; + accelerationStructureBuildRangeInfo.firstVertex = 0; + accelerationStructureBuildRangeInfo.transformOffset = 0; + std::vector accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo }; - std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo }; - - if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands) + if (accelerationStructureFeatures.accelerationStructureHostCommands) { // Implementation supports building acceleration structure building on host - VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data())); + vkBuildAccelerationStructuresKHR( + device, + VK_NULL_HANDLE, + 1, + &accelerationBuildGeometryInfo, + accelerationBuildStructureRangeInfos.data()); } else { // Acceleration structure needs to be build on the device VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()); + 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.accelerationStructure; - - bottomLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); - deleteScratchBuffer(scratchBuffer); } @@ -365,132 +167,133 @@ public: */ void createTopLevelAccelerationStructure() { - VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{}; - accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; - accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - accelerationCreateGeometryInfo.maxPrimitiveCount = 1; - accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE; - - VkAccelerationStructureCreateInfoKHR accelerationCI{}; - accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationCI.maxGeometryCount = 1; - accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo; - VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &topLevelAS.accelerationStructure)); - - // Bind object memory to the top level acceleration structure - topLevelAS.objectMemory = createObjectMemory(topLevelAS.accelerationStructure); - - VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{}; - bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - bindAccelerationMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure; - bindAccelerationMemoryInfo.memory = topLevelAS.objectMemory.memory; - VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo)); - - VkTransformMatrixKHR 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 }; VkAccelerationStructureInstanceKHR instance{}; - instance.transform = transform_matrix; + 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.handle; + 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_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(instance), + sizeof(VkAccelerationStructureInstanceKHR), &instance)); - VkDeviceOrHostAddressConstKHR instance_data_device_address{}; - instance_data_device_address.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer); + VkDeviceOrHostAddressConstKHR instanceDataDeviceAddress{}; + instanceDataDeviceAddress.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer); - VkAccelerationStructureGeometryKHR accelerationStructureGeometry{}; - accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + VkAccelerationStructureGeometryKHR accelerationStructureGeometry = vks::initializers::accelerationStructureGeometryKHR(); 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.deviceAddress = instance_data_device_address.deviceAddress; + accelerationStructureGeometry.geometry.instances.data = instanceDataDeviceAddress; - std::vector acceleration_geometries = { accelerationStructureGeometry }; - VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data(); + // Get size info + VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); + 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 = vks::initializers::accelerationStructureBuildSizesInfoKHR(); + vkGetAccelerationStructureBuildSizesKHR( + device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &accelerationStructureBuildGeometryInfo, + &primitive_count, + &accelerationStructureBuildSizesInfo); + + createAccelerationStructure(topLevelAS, VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, accelerationStructureBuildSizesInfo); // Create a small scratch buffer used during build of the top level acceleration structure - RayTracingScratchBuffer scratchBuffer = createScratchBuffer(topLevelAS.accelerationStructure); + ScratchBuffer scratchBuffer = createScratchBuffer(accelerationStructureBuildSizesInfo.buildScratchSize); - VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{}; - accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationBuildGeometryInfo.update = VK_FALSE; - accelerationBuildGeometryInfo.srcAccelerationStructure = VK_NULL_HANDLE; - accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.accelerationStructure; - accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE; + accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.handle; accelerationBuildGeometryInfo.geometryCount = 1; - accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries; + accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry; accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress; - VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{}; - accelerationBuildOffsetInfo.primitiveCount = 1; - accelerationBuildOffsetInfo.primitiveOffset = 0x0; - accelerationBuildOffsetInfo.firstVertex = 0; - accelerationBuildOffsetInfo.transformOffset = 0x0; - std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo }; + VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{}; + accelerationStructureBuildRangeInfo.primitiveCount = 1; + accelerationStructureBuildRangeInfo.primitiveOffset = 0; + accelerationStructureBuildRangeInfo.firstVertex = 0; + accelerationStructureBuildRangeInfo.transformOffset = 0; + std::vector accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo }; - if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands) + if (accelerationStructureFeatures.accelerationStructureHostCommands) { // Implementation supports building acceleration structure building on host - VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data())); + vkBuildAccelerationStructuresKHR( + device, + VK_NULL_HANDLE, + 1, + &accelerationBuildGeometryInfo, + accelerationBuildStructureRangeInfos.data()); } else { // Acceleration structure needs to be build on the device VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()); + 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.accelerationStructure; - - topLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); - deleteScratchBuffer(scratchBuffer); instancesBuffer.destroy(); } /* - Create the Shader Binding Table that binds the programs and top-level acceleration structure + 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() { + void createShaderBindingTables() { + const uint32_t handleSize = rayTracingPipelineProperties.shaderGroupHandleSize; + const uint32_t handleAlignment = rayTracingPipelineProperties.shaderGroupHandleAlignment; const uint32_t groupCount = static_cast(shaderGroups.size()); + const uint32_t sbtSize = handleSize * groupCount; - const uint32_t sbtSize = rayTracingProperties.shaderGroupBaseAlignment * groupCount; - VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &shaderBindingTable, sbtSize)); - shaderBindingTable.map(); - - // Write the shader handles to the shader binding table std::vector shaderHandleStorage(sbtSize); VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data())); - auto* data = static_cast(shaderBindingTable.mapped); - // This part is required, as the alignment and handle size may differ - for (uint32_t i = 0; i < groupCount; i++) - { - memcpy(data, shaderHandleStorage.data() + i * rayTracingProperties.shaderGroupHandleSize, rayTracingProperties.shaderGroupHandleSize); - data += rayTracingProperties.shaderGroupBaseAlignment; - } - shaderBindingTable.unmap(); + createShaderBindingTable(shaderBindingTables.raygen, 1); + createShaderBindingTable(shaderBindingTables.miss, 1); + createShaderBindingTable(shaderBindingTables.hit, 1); + + // Copy handles + memcpy(shaderBindingTables.raygen.mapped, shaderHandleStorage.data(), handleSize); + memcpy(shaderBindingTables.miss.mapped, shaderHandleStorage.data() + handleAlignment, handleSize); + memcpy(shaderBindingTables.hit.mapped, shaderHandleStorage.data() + handleAlignment * 2, handleSize); } /* @@ -510,10 +313,9 @@ public: 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; + VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo = vks::initializers::writeDescriptorSetAccelerationStructureKHR(); descriptorAccelerationStructureInfo.accelerationStructureCount = 1; - descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure; + descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.handle; VkWriteDescriptorSet accelerationStructureWrite{}; accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -524,29 +326,21 @@ public: accelerationStructureWrite.descriptorCount = 1; accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; - VkDescriptorImageInfo storageImageDescriptor{}; - storageImageDescriptor.imageView = storageImage.view; - storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - VkDescriptorBufferInfo vertexBufferDescriptor{}; - vertexBufferDescriptor.buffer = scene.vertices.buffer; - vertexBufferDescriptor.range = VK_WHOLE_SIZE; - - VkDescriptorBufferInfo indexBufferDescriptor{}; - indexBufferDescriptor.buffer = scene.indices.buffer; - indexBufferDescriptor.range = VK_WHOLE_SIZE; - - 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); - VkWriteDescriptorSet vertexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor); - VkWriteDescriptorSet indexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor); + VkDescriptorImageInfo storageImageDescriptor{ VK_NULL_HANDLE, storageImage.view, VK_IMAGE_LAYOUT_GENERAL }; + VkDescriptorBufferInfo vertexBufferDescriptor{ scene.vertices.buffer, 0, VK_WHOLE_SIZE }; + VkDescriptorBufferInfo indexBufferDescriptor{ scene.indices.buffer, 0, VK_WHOLE_SIZE }; std::vector writeDescriptorSets = { + // Binding 0: Top level acceleration structure accelerationStructureWrite, - resultImageWrite, - uniformBufferWrite, - vertexBufferWrite, - indexBufferWrite + // Binding 0: Top level acceleration structure + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor), + // Binding 1: Ray tracing result image + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor), + // Binding 1: Ray tracing result image + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor), + // Binding 1: Ray tracing result image + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE); } @@ -556,112 +350,82 @@ public: */ 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 | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + std::vector setLayoutBindings = { + // Binding 0: Acceleration structure + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 0), + // Binding 1: Storage image + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_RAYGEN_BIT_KHR, 1), + // Binding 2: Uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, 2), + // Binding 3: Vertex buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 3), + // Binding 4: Index buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 4), + }; - VkDescriptorSetLayoutBinding resultImageLayoutBinding{}; - resultImageLayoutBinding.binding = 1; - resultImageLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - resultImageLayoutBinding.descriptorCount = 1; - resultImageLayoutBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR; + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayout)); - VkDescriptorSetLayoutBinding uniformBufferBinding{}; - uniformBufferBinding.binding = 2; - uniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uniformBufferBinding.descriptorCount = 1; - uniformBufferBinding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR; - - VkDescriptorSetLayoutBinding vertexBufferBinding{}; - vertexBufferBinding.binding = 3; - vertexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - vertexBufferBinding.descriptorCount = 1; - vertexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - - VkDescriptorSetLayoutBinding indexBufferBinding{}; - indexBufferBinding.binding = 4; - indexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - indexBufferBinding.descriptorCount = 1; - indexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - - std::vector bindings({ - accelerationStructureLayoutBinding, - resultImageLayoutBinding, - uniformBufferBinding, - vertexBufferBinding, - indexBufferBinding - }); - - VkDescriptorSetLayoutCreateInfo layoutInfo{}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = static_cast(bindings.size()); - layoutInfo.pBindings = bindings.data(); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout)); - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{}; - pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCreateInfo.setLayoutCount = 1; - pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout; - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - - const uint32_t shaderIndexRaygen = 0; - const uint32_t shaderIndexMiss = 1; - const uint32_t shaderIndexClosestHit = 2; - - std::array shaderStages; - shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "raytracingreflections/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR); - shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "raytracingreflections/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR); - shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "raytracingreflections/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - // Pass recursion depth for reflections to ray generation shader via specialization constant - VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t)); - uint32_t maxRecursion = 4; - VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(maxRecursion), &maxRecursion); - shaderStages[shaderIndexRaygen].pSpecializationInfo = &specializationInfo; + VkPipelineLayoutCreateInfo pPipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCI, nullptr, &pipelineLayout)); /* Setup ray tracing shader groups */ - VkRayTracingShaderGroupCreateInfoKHR raygenGroupCI{}; - raygenGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - raygenGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - raygenGroupCI.generalShader = shaderIndexRaygen; - raygenGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR; - raygenGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - raygenGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(raygenGroupCI); + std::vector shaderStages; - VkRayTracingShaderGroupCreateInfoKHR missGroupCI{}; - missGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - missGroupCI.generalShader = shaderIndexMiss; - missGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR; - missGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - missGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(missGroupCI); + // Ray generation group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingreflections/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR)); + // Pass recursion depth for reflections to ray generation shader via specialization constant + VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t)); + uint32_t maxRecursion = 4; + VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(maxRecursion), &maxRecursion); + shaderStages.back().pSpecializationInfo = &specializationInfo; + 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(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); + } - VkRayTracingShaderGroupCreateInfoKHR closesHitGroupCI{}; - closesHitGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - closesHitGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - closesHitGroupCI.generalShader = VK_SHADER_UNUSED_KHR; - closesHitGroupCI.closestHitShader = shaderIndexClosestHit; - closesHitGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - closesHitGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(closesHitGroupCI); + // Miss group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingreflections/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(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); + } - VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI{}; - rayTracingPipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + // Closest hit group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingreflections/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(shaderStages.size()) - 1; + shaderGroup.anyHitShader = VK_SHADER_UNUSED_KHR; + shaderGroup.intersectionShader = VK_SHADER_UNUSED_KHR; + shaderGroups.push_back(shaderGroup); + } + + VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI = vks::initializers::rayTracingPipelineCreateInfoKHR(); rayTracingPipelineCI.stageCount = static_cast(shaderStages.size()); rayTracingPipelineCI.pStages = shaderStages.data(); rayTracingPipelineCI.groupCount = static_cast(shaderGroups.size()); rayTracingPipelineCI.pGroups = shaderGroups.data(); - rayTracingPipelineCI.maxRecursionDepth = 4; + rayTracingPipelineCI.maxPipelineRayRecursionDepth = 4; rayTracingPipelineCI.layout = pipelineLayout; - rayTracingPipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; - VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline)); + VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline)); } /* @@ -685,12 +449,8 @@ public: */ void handleResize() { - // Delete allocated resources - vkDestroyImageView(device, storageImage.view, nullptr); - vkDestroyImage(device, storageImage.image, nullptr); - vkFreeMemory(device, storageImage.memory, nullptr); // Recreate image - createStorageImage(); + createStorageImage(swapChain.colorFormat, { width, height, 1 }); // 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); @@ -722,36 +482,18 @@ public: vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout, 0, 1, &descriptorSet, 0, 0); /* - Setup the buffer regions pointing to the shaders in our shader binding table + Dispatch the ray tracing commands */ - const VkDeviceSize sbtSize = rayTracingProperties.shaderGroupBaseAlignment * (VkDeviceSize)shaderGroups.size(); - - VkStridedBufferRegionKHR raygenShaderSBTEntry{}; - raygenShaderSBTEntry.buffer = shaderBindingTable.buffer; - raygenShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_RAYGEN_GROUP); - raygenShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - raygenShaderSBTEntry.size = sbtSize; - - VkStridedBufferRegionKHR missShaderSBTEntry{}; - missShaderSBTEntry.buffer = shaderBindingTable.buffer; - missShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_MISS_GROUP); - missShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - missShaderSBTEntry.size = sbtSize; - - VkStridedBufferRegionKHR hitShaderSBTEntry{}; - hitShaderSBTEntry.buffer = shaderBindingTable.buffer; - hitShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_CLOSEST_HIT_GROUP); - hitShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - hitShaderSBTEntry.size = sbtSize; - - VkStridedBufferRegionKHR callableShaderSBTEntry{}; + 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); + VkStridedDeviceAddressRegionKHR emptySbtEntry = {}; vkCmdTraceRaysKHR( drawCmdBuffers[i], - &raygenShaderSBTEntry, - &missShaderSBTEntry, - &hitShaderSBTEntry, - &callableShaderSBTEntry, + &shaderBindingTables.raygen.stridedDeviceAddressRegion, + &shaderBindingTables.miss.stridedDeviceAddressRegion, + &shaderBindingTables.hit.stridedDeviceAddressRegion, + &emptySbtEntry, width, height, 1); @@ -825,52 +567,29 @@ public: enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE; - enabledRayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR; - enabledRayTracingFeatures.rayTracing = VK_TRUE; - enabledRayTracingFeatures.pNext = &enabledBufferDeviceAddresFeatures; + enabledRayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + enabledRayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE; + enabledRayTracingPipelineFeatures.pNext = &enabledBufferDeviceAddresFeatures; - deviceCreatepNextChain = &enabledRayTracingFeatures; + enabledAccelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + enabledAccelerationStructureFeatures.accelerationStructure = VK_TRUE; + enabledAccelerationStructureFeatures.pNext = &enabledRayTracingPipelineFeatures; + + deviceCreatepNextChain = &enabledAccelerationStructureFeatures; } void prepare() { - VulkanExampleBase::prepare(); - - // Query the ray tracing properties of the current implementation, we will need them later on - rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR; - VkPhysicalDeviceProperties2 deviceProps2{}; - deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - deviceProps2.pNext = &rayTracingProperties; - vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2); - - // Query the ray tracing properties of the current implementation, we will need them later on - rayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR; - VkPhysicalDeviceFeatures2 deviceFeatures2{}; - deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - deviceFeatures2.pNext = &rayTracingFeatures; - vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2); - - // Get the function pointers required for ray tracing - vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR")); - vkBindAccelerationStructureMemoryKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryKHR")); - vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR")); - vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR")); - vkGetAccelerationStructureMemoryRequirementsKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsKHR")); - vkCmdBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureKHR")); - vkBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructureKHR")); - vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR")); - vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR")); - vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR")); - vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR")); + VulkanRaytracingSample::prepare(); // Create the acceleration structures used to render the ray traced scene createBottomLevelAccelerationStructure(); createTopLevelAccelerationStructure(); - createStorageImage(); + createStorageImage(swapChain.colorFormat, { width, height, 1 }); createUniformBuffer(); createRayTracingPipeline(); - createShaderBindingTable(); + createShaderBindingTables(); createDescriptorSets(); buildCommandBuffers(); prepared = true; diff --git a/examples/raytracingshadows/raytracingshadows.cpp b/examples/raytracingshadows/raytracingshadows.cpp index 75defd8b..a3e7df6c 100644 --- a/examples/raytracingshadows/raytracingshadows.cpp +++ b/examples/raytracingshadows/raytracingshadows.cpp @@ -1,5 +1,5 @@ /* -* Vulkan Example - Hardware accelerated ray tracing shadow example using VK_KHR_ray_traying +* Vulkan Example - Hardware accelerated ray tracing shadow example * * Renders a complex scene using multiple hit and miss shaders for implementing shadows * @@ -8,69 +8,21 @@ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ -#define VK_ENABLE_BETA_EXTENSIONS - -#include "vulkanexamplebase.h" +#include "VulkanRaytracingSample.h" #include "VulkanglTFModel.h" -// Ray tracing utility structures, see ray tracing basic sample for details -struct RayTracingScratchBuffer -{ - uint64_t deviceAddress = 0; - VkBuffer buffer = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; -}; - -struct RayTracingObjectMemory -{ - uint64_t deviceAddress = 0; - VkDeviceMemory memory = VK_NULL_HANDLE; -}; - -struct AccelerationStructure { - VkAccelerationStructureKHR accelerationStructure; - uint64_t handle; - RayTracingObjectMemory objectMemory; -}; - -// Indices for the different ray tracing groups used in this example -#define INDEX_RAYGEN_GROUP 0 -#define INDEX_MISS_GROUP 1 -#define INDEX_CLOSEST_HIT_GROUP 3 - -class VulkanExample : public VulkanExampleBase +class VulkanExample : public VulkanRaytracingSample { public: - PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; - PFN_vkBindAccelerationStructureMemoryKHR vkBindAccelerationStructureMemoryKHR; - PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; - PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; - PFN_vkGetAccelerationStructureMemoryRequirementsKHR vkGetAccelerationStructureMemoryRequirementsKHR; - PFN_vkCmdBuildAccelerationStructureKHR vkCmdBuildAccelerationStructureKHR; - PFN_vkBuildAccelerationStructureKHR vkBuildAccelerationStructureKHR; - PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; - PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; - PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; - PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; - - VkPhysicalDeviceRayTracingPropertiesKHR rayTracingProperties{}; - VkPhysicalDeviceRayTracingFeaturesKHR rayTracingFeatures{}; - - VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{}; - VkPhysicalDeviceRayTracingFeaturesKHR enabledRayTracingFeatures{}; - AccelerationStructure bottomLevelAS; AccelerationStructure topLevelAS; std::vector shaderGroups{}; - vks::Buffer shaderBindingTable; - - struct StorageImage { - VkDeviceMemory memory; - VkImage image; - VkImageView view; - VkFormat format; - } storageImage; + struct ShaderBindingTables { + ShaderBindingTable raygen; + ShaderBindingTable miss; + ShaderBindingTable hit; + } shaderBindingTables; struct UniformData { glm::mat4 viewInverse; @@ -87,7 +39,8 @@ public: vkglTF::Model scene; - VulkanExample() : VulkanExampleBase() + // This sample is derived from an extended base class that saves most of the ray tracing setup boiler plate + VulkanExample() : VulkanRaytracingSample() { title = "Ray traced shadows"; settings.overlay = false; @@ -96,17 +49,7 @@ public: 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, 3.0f, -10.0f)); - // Enable instance and device extensions required to use VK_KHR_ray_tracing - enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME); - 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); - enabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); - // We require Vulkan 1.2 for ray tracing - apiVersion = VK_API_VERSION_1_2; + enableExtensions(); } ~VulkanExample() @@ -114,146 +57,13 @@ public: 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); - vkDestroyAccelerationStructureKHR(device, bottomLevelAS.accelerationStructure, nullptr); - vkDestroyAccelerationStructureKHR(device, topLevelAS.accelerationStructure, nullptr); - shaderBindingTable.destroy(); + deleteStorageImage(); + deleteAccelerationStructure(bottomLevelAS); + deleteAccelerationStructure(topLevelAS); + shaderBindingTables.raygen.destroy(); + shaderBindingTables.miss.destroy(); + shaderBindingTables.hit.destroy(); ubo.destroy(); - deleteObjectMemory(bottomLevelAS.objectMemory); - deleteObjectMemory(topLevelAS.objectMemory); - } - - /* - Ray tracing utility functions, see ray tracing basic sample for details - */ - RayTracingScratchBuffer createScratchBuffer(VkAccelerationStructureKHR accelerationStructure) - { - RayTracingScratchBuffer scratchBuffer{}; - VkMemoryRequirements2 memoryRequirements2{}; - memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{}; - accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR; - accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - accelerationStructureMemoryRequirements.accelerationStructure = accelerationStructure; - vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2); - VkBufferCreateInfo bufferCI{}; - bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCI.size = memoryRequirements2.memoryRequirements.size; - bufferCI.usage = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCI, nullptr, &scratchBuffer.buffer)); - VkMemoryRequirements memoryRequirements{}; - vkGetBufferMemoryRequirements(device, scratchBuffer.buffer, &memoryRequirements); - VkMemoryAllocateFlagsInfo memoryAllocateFI{}; - memoryAllocateFI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - memoryAllocateFI.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.pNext = &memoryAllocateFI; - memoryAI.allocationSize = memoryRequirements.size; - memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &scratchBuffer.memory)); - VK_CHECK_RESULT(vkBindBufferMemory(device, scratchBuffer.buffer, scratchBuffer.memory, 0)); - VkBufferDeviceAddressInfoKHR buffer_device_address_info{}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.buffer = scratchBuffer.buffer; - scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(device, &buffer_device_address_info); - return scratchBuffer; - } - - void deleteScratchBuffer(RayTracingScratchBuffer& scratchBuffer) - { - if (scratchBuffer.memory != VK_NULL_HANDLE) { - vkFreeMemory(device, scratchBuffer.memory, nullptr); - } - if (scratchBuffer.buffer != VK_NULL_HANDLE) { - vkDestroyBuffer(device, scratchBuffer.buffer, nullptr); - } - } - - RayTracingObjectMemory createObjectMemory(VkAccelerationStructureKHR acceleration_structure) - { - RayTracingObjectMemory objectMemory{}; - VkMemoryRequirements2 memoryRequirements2{}; - memoryRequirements2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - VkAccelerationStructureMemoryRequirementsInfoKHR accelerationStructureMemoryRequirements{}; - accelerationStructureMemoryRequirements.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR; - accelerationStructureMemoryRequirements.type = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR; - accelerationStructureMemoryRequirements.buildType = VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR; - accelerationStructureMemoryRequirements.accelerationStructure = acceleration_structure; - vkGetAccelerationStructureMemoryRequirementsKHR(device, &accelerationStructureMemoryRequirements, &memoryRequirements2); - VkMemoryRequirements memoryRequirements = memoryRequirements2.memoryRequirements; - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.allocationSize = memoryRequirements.size; - memoryAI.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device, &memoryAI, nullptr, &objectMemory.memory)); - return objectMemory; - } - - void deleteObjectMemory(RayTracingObjectMemory& objectMemory) - { - if (objectMemory.memory != VK_NULL_HANDLE) { - vkFreeMemory(device, objectMemory.memory, nullptr); - } - } - - 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); } /* @@ -263,99 +73,92 @@ public: { // Instead of a simple triangle, we'll be loading a more complex scene for this example // The shaders are accessing the vertex and index buffers of the scene, so the proper usage flag has to be set on the vertex and index buffers for the scene - vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + vkglTF::memoryPropertyFlags = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; const uint32_t glTFLoadingFlags = vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::PreMultiplyVertexColors | vkglTF::FileLoadingFlags::FlipY; scene.loadFromFile(getAssetPath() + "models/vulkanscene_shadow.gltf", vulkanDevice, queue, glTFLoadingFlags); - const uint32_t numTriangles = static_cast(scene.indices.count) / 3; - VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{}; VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{}; vertexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.vertices.buffer); indexBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(scene.indices.buffer); - VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{}; - accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; - accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - accelerationCreateGeometryInfo.maxPrimitiveCount = numTriangles; - accelerationCreateGeometryInfo.indexType = VK_INDEX_TYPE_UINT32; - accelerationCreateGeometryInfo.maxVertexCount = static_cast(scene.vertices.count); - accelerationCreateGeometryInfo.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; - accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE; + uint32_t numTriangles = static_cast(scene.indices.count) / 3; + uint32_t maxVertex = scene.vertices.count; - VkAccelerationStructureCreateInfoKHR accelerationCI{}; - accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationCI.maxGeometryCount = 1; - accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo; - VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &bottomLevelAS.accelerationStructure)); - - // Bind object memory to the top level acceleration structure - bottomLevelAS.objectMemory = createObjectMemory(bottomLevelAS.accelerationStructure); - - VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{}; - bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - bindAccelerationMemoryInfo.accelerationStructure = bottomLevelAS.accelerationStructure; - bindAccelerationMemoryInfo.memory = bottomLevelAS.objectMemory.memory; - VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo)); - - VkAccelerationStructureGeometryKHR accelerationStructureGeometry{}; - accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + // Build + VkAccelerationStructureGeometryKHR accelerationStructureGeometry = vks::initializers::accelerationStructureGeometryKHR(); 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.deviceAddress = vertexBufferDeviceAddress.deviceAddress; + accelerationStructureGeometry.geometry.triangles.vertexData = vertexBufferDeviceAddress; + accelerationStructureGeometry.geometry.triangles.maxVertex = maxVertex; accelerationStructureGeometry.geometry.triangles.vertexStride = sizeof(vkglTF::Vertex); accelerationStructureGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; - accelerationStructureGeometry.geometry.triangles.indexData.deviceAddress = indexBufferDeviceAddress.deviceAddress; + accelerationStructureGeometry.geometry.triangles.indexData = indexBufferDeviceAddress; + accelerationStructureGeometry.geometry.triangles.transformData.deviceAddress = 0; + accelerationStructureGeometry.geometry.triangles.transformData.hostAddress = nullptr; - std::vector acceleration_geometries = { accelerationStructureGeometry }; - VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data(); + // Get size info + VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); + 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; + + VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo = vks::initializers::accelerationStructureBuildSizesInfoKHR(); + vkGetAccelerationStructureBuildSizesKHR( + device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &accelerationStructureBuildGeometryInfo, + &numTriangles, + &accelerationStructureBuildSizesInfo); + + createAccelerationStructure(bottomLevelAS, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, accelerationStructureBuildSizesInfo); // Create a small scratch buffer used during build of the bottom level acceleration structure - RayTracingScratchBuffer scratchBuffer = createScratchBuffer(bottomLevelAS.accelerationStructure); + ScratchBuffer scratchBuffer = createScratchBuffer(accelerationStructureBuildSizesInfo.buildScratchSize); - VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{}; - accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationBuildGeometryInfo.update = VK_FALSE; - accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.accelerationStructure; - accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE; + accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + accelerationBuildGeometryInfo.dstAccelerationStructure = bottomLevelAS.handle; accelerationBuildGeometryInfo.geometryCount = 1; - accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries; + accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry; accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress; - VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{}; - accelerationBuildOffsetInfo.primitiveCount = numTriangles; - accelerationBuildOffsetInfo.primitiveOffset = 0x0; - accelerationBuildOffsetInfo.firstVertex = 0; - accelerationBuildOffsetInfo.transformOffset = 0x0; + VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{}; + accelerationStructureBuildRangeInfo.primitiveCount = numTriangles; + accelerationStructureBuildRangeInfo.primitiveOffset = 0; + accelerationStructureBuildRangeInfo.firstVertex = 0; + accelerationStructureBuildRangeInfo.transformOffset = 0; + std::vector accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo }; - std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo }; - - if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands) + if (accelerationStructureFeatures.accelerationStructureHostCommands) { // Implementation supports building acceleration structure building on host - VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data())); + // Implementation supports building acceleration structure building on host + vkBuildAccelerationStructuresKHR( + device, + VK_NULL_HANDLE, + 1, + &accelerationBuildGeometryInfo, + accelerationBuildStructureRangeInfos.data()); } else { // Acceleration structure needs to be build on the device VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()); + 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.accelerationStructure; - - bottomLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); - deleteScratchBuffer(scratchBuffer); } @@ -364,132 +167,138 @@ public: */ void createTopLevelAccelerationStructure() { - VkAccelerationStructureCreateGeometryTypeInfoKHR accelerationCreateGeometryInfo{}; - accelerationCreateGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR; - accelerationCreateGeometryInfo.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - accelerationCreateGeometryInfo.maxPrimitiveCount = 1; - accelerationCreateGeometryInfo.allowsTransforms = VK_FALSE; - - VkAccelerationStructureCreateInfoKHR accelerationCI{}; - accelerationCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - accelerationCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - accelerationCI.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationCI.maxGeometryCount = 1; - accelerationCI.pGeometryInfos = &accelerationCreateGeometryInfo; - VK_CHECK_RESULT(vkCreateAccelerationStructureKHR(device, &accelerationCI, nullptr, &topLevelAS.accelerationStructure)); - - // Bind object memory to the top level acceleration structure - topLevelAS.objectMemory = createObjectMemory(topLevelAS.accelerationStructure); - - VkBindAccelerationStructureMemoryInfoKHR bindAccelerationMemoryInfo{}; - bindAccelerationMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR; - bindAccelerationMemoryInfo.accelerationStructure = topLevelAS.accelerationStructure; - bindAccelerationMemoryInfo.memory = topLevelAS.objectMemory.memory; - VK_CHECK_RESULT(vkBindAccelerationStructureMemoryKHR(device, 1, &bindAccelerationMemoryInfo)); - - VkTransformMatrixKHR 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 }; VkAccelerationStructureInstanceKHR instance{}; - instance.transform = transform_matrix; + 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.handle; + 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_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(instance), + sizeof(VkAccelerationStructureInstanceKHR), &instance)); - VkDeviceOrHostAddressConstKHR instance_data_device_address{}; - instance_data_device_address.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer); + VkDeviceOrHostAddressConstKHR instanceDataDeviceAddress{}; + instanceDataDeviceAddress.deviceAddress = getBufferDeviceAddress(instancesBuffer.buffer); - VkAccelerationStructureGeometryKHR accelerationStructureGeometry{}; - accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + VkAccelerationStructureGeometryKHR accelerationStructureGeometry = vks::initializers::accelerationStructureGeometryKHR(); 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.deviceAddress = instance_data_device_address.deviceAddress; + accelerationStructureGeometry.geometry.instances.data = instanceDataDeviceAddress; - std::vector acceleration_geometries = { accelerationStructureGeometry }; - VkAccelerationStructureGeometryKHR* acceleration_structure_geometries = acceleration_geometries.data(); + // Get size info + VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); + 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 = vks::initializers::accelerationStructureBuildSizesInfoKHR(); + vkGetAccelerationStructureBuildSizesKHR( + device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &accelerationStructureBuildGeometryInfo, + &primitive_count, + &accelerationStructureBuildSizesInfo); + + // @todo: as return value? + createAccelerationStructure(topLevelAS, VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, accelerationStructureBuildSizesInfo); // Create a small scratch buffer used during build of the top level acceleration structure - RayTracingScratchBuffer scratchBuffer = createScratchBuffer(topLevelAS.accelerationStructure); + ScratchBuffer scratchBuffer = createScratchBuffer(accelerationStructureBuildSizesInfo.buildScratchSize); - VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{}; - accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo = vks::initializers::accelerationStructureBuildGeometryInfoKHR(); accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - accelerationBuildGeometryInfo.update = VK_FALSE; - accelerationBuildGeometryInfo.srcAccelerationStructure = VK_NULL_HANDLE; - accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.accelerationStructure; - accelerationBuildGeometryInfo.geometryArrayOfPointers = VK_FALSE; + accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + accelerationBuildGeometryInfo.dstAccelerationStructure = topLevelAS.handle; accelerationBuildGeometryInfo.geometryCount = 1; - accelerationBuildGeometryInfo.ppGeometries = &acceleration_structure_geometries; + accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry; accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.deviceAddress; - VkAccelerationStructureBuildOffsetInfoKHR accelerationBuildOffsetInfo{}; - accelerationBuildOffsetInfo.primitiveCount = 1; - accelerationBuildOffsetInfo.primitiveOffset = 0x0; - accelerationBuildOffsetInfo.firstVertex = 0; - accelerationBuildOffsetInfo.transformOffset = 0x0; - std::vector accelerationBuildOffsets = { &accelerationBuildOffsetInfo }; + VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{}; + accelerationStructureBuildRangeInfo.primitiveCount = 1; + accelerationStructureBuildRangeInfo.primitiveOffset = 0; + accelerationStructureBuildRangeInfo.firstVertex = 0; + accelerationStructureBuildRangeInfo.transformOffset = 0; + std::vector accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo }; - if (rayTracingFeatures.rayTracingHostAccelerationStructureCommands) + if (accelerationStructureFeatures.accelerationStructureHostCommands) { // Implementation supports building acceleration structure building on host - VK_CHECK_RESULT(vkBuildAccelerationStructureKHR(device, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data())); + // Implementation supports building acceleration structure building on host + vkBuildAccelerationStructuresKHR( + device, + VK_NULL_HANDLE, + 1, + &accelerationBuildGeometryInfo, + accelerationBuildStructureRangeInfos.data()); } else { // Acceleration structure needs to be build on the device VkCommandBuffer commandBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - vkCmdBuildAccelerationStructureKHR(commandBuffer, 1, &accelerationBuildGeometryInfo, accelerationBuildOffsets.data()); + 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.accelerationStructure; - - topLevelAS.handle = vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo); - deleteScratchBuffer(scratchBuffer); instancesBuffer.destroy(); } + /* - Create the Shader Binding Table that binds the programs and top-level acceleration structure + 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() { + void createShaderBindingTables() { + const uint32_t handleSize = rayTracingPipelineProperties.shaderGroupHandleSize; + const uint32_t handleAlignment = rayTracingPipelineProperties.shaderGroupHandleAlignment; const uint32_t groupCount = static_cast(shaderGroups.size()); + const uint32_t sbtSize = handleSize * groupCount; - const uint32_t sbtSize = rayTracingProperties.shaderGroupBaseAlignment * groupCount; - VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &shaderBindingTable, sbtSize)); - shaderBindingTable.map(); - - // Write the shader handles to the shader binding table std::vector shaderHandleStorage(sbtSize); VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data())); - auto* data = static_cast(shaderBindingTable.mapped); - // This part is required, as the alignment and handle size may differ - for (uint32_t i = 0; i < groupCount; i++) - { - memcpy(data, shaderHandleStorage.data() + i * rayTracingProperties.shaderGroupHandleSize, rayTracingProperties.shaderGroupHandleSize); - data += rayTracingProperties.shaderGroupBaseAlignment; - } - shaderBindingTable.unmap(); + createShaderBindingTable(shaderBindingTables.raygen, 1); + // We are using two miss shaders + createShaderBindingTable(shaderBindingTables.miss, 2); + createShaderBindingTable(shaderBindingTables.hit, 1); + + // Copy handles + memcpy(shaderBindingTables.raygen.mapped, shaderHandleStorage.data(), handleSize); + // We are using two miss shaders, so we need to get two handles for the miss shader binding table + memcpy(shaderBindingTables.miss.mapped, shaderHandleStorage.data() + handleAlignment, handleSize * 2); + memcpy(shaderBindingTables.hit.mapped, shaderHandleStorage.data() + handleAlignment * 3, handleSize); } /* @@ -509,10 +318,9 @@ public: 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; + VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo = vks::initializers::writeDescriptorSetAccelerationStructureKHR(); descriptorAccelerationStructureInfo.accelerationStructureCount = 1; - descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.accelerationStructure; + descriptorAccelerationStructureInfo.pAccelerationStructures = &topLevelAS.handle; VkWriteDescriptorSet accelerationStructureWrite{}; accelerationStructureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -523,29 +331,21 @@ public: accelerationStructureWrite.descriptorCount = 1; accelerationStructureWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; - VkDescriptorImageInfo storageImageDescriptor{}; - storageImageDescriptor.imageView = storageImage.view; - storageImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - VkDescriptorBufferInfo vertexBufferDescriptor{}; - vertexBufferDescriptor.buffer = scene.vertices.buffer; - vertexBufferDescriptor.range = VK_WHOLE_SIZE; - - VkDescriptorBufferInfo indexBufferDescriptor{}; - indexBufferDescriptor.buffer = scene.indices.buffer; - indexBufferDescriptor.range = VK_WHOLE_SIZE; - - 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); - VkWriteDescriptorSet vertexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor); - VkWriteDescriptorSet indexBufferWrite = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor); + VkDescriptorImageInfo storageImageDescriptor{ VK_NULL_HANDLE, storageImage.view, VK_IMAGE_LAYOUT_GENERAL }; + VkDescriptorBufferInfo vertexBufferDescriptor{ scene.vertices.buffer, 0, VK_WHOLE_SIZE }; + VkDescriptorBufferInfo indexBufferDescriptor{ scene.indices.buffer, 0, VK_WHOLE_SIZE }; std::vector writeDescriptorSets = { + // Binding 0: Top level acceleration structure accelerationStructureWrite, - resultImageWrite, - uniformBufferWrite, - vertexBufferWrite, - indexBufferWrite + // Binding 0: Top level acceleration structure + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, &storageImageDescriptor), + // Binding 1: Ray tracing result image + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2, &ubo.descriptor), + // Binding 1: Ray tracing result image + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, &vertexBufferDescriptor), + // Binding 1: Ray tracing result image + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4, &indexBufferDescriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, VK_NULL_HANDLE); } @@ -555,111 +355,81 @@ public: */ 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 | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + std::vector setLayoutBindings = { + // Binding 0: Acceleration structure + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 0), + // Binding 1: Storage image + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_RAYGEN_BIT_KHR, 1), + // Binding 2: Uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, 2), + // Binding 3: Vertex buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 3), + // Binding 4: Index buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, 4), + }; - 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 | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - - VkDescriptorSetLayoutBinding vertexBufferBinding{}; - vertexBufferBinding.binding = 3; - vertexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - vertexBufferBinding.descriptorCount = 1; - vertexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - - VkDescriptorSetLayoutBinding indexBufferBinding{}; - indexBufferBinding.binding = 4; - indexBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - indexBufferBinding.descriptorCount = 1; - indexBufferBinding.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - - std::vector bindings({ - accelerationStructureLayoutBinding, - resultImageLayoutBinding, - uniformBufferBinding, - vertexBufferBinding, - indexBufferBinding - }); - - VkDescriptorSetLayoutCreateInfo layoutInfo{}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = static_cast(bindings.size()); - layoutInfo.pBindings = bindings.data(); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout)); - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{}; - pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCreateInfo.setLayoutCount = 1; - pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout; - - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); - - const uint32_t shaderIndexRaygen = 0; - const uint32_t shaderIndexMiss = 1; - const uint32_t shaderIndexShadowMiss = 2; - const uint32_t shaderIndexClosestHit = 3; - - std::array shaderStages; - shaderStages[shaderIndexRaygen] = loadShader(getShadersPath() + "raytracingshadows/raygen.rgen.spv", VK_SHADER_STAGE_RAYGEN_BIT_KHR); - shaderStages[shaderIndexMiss] = loadShader(getShadersPath() + "raytracingshadows/miss.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR); - shaderStages[shaderIndexShadowMiss] = loadShader(getShadersPath() + "raytracingshadows/shadow.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR); - shaderStages[shaderIndexClosestHit] = loadShader(getShadersPath() + "raytracingshadows/closesthit.rchit.spv", VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayout)); + VkPipelineLayoutCreateInfo pPipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCI, nullptr, &pipelineLayout)); + /* Setup ray tracing shader groups */ - VkRayTracingShaderGroupCreateInfoKHR raygenGroupCI{}; - raygenGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - raygenGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - raygenGroupCI.generalShader = shaderIndexRaygen; - raygenGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR; - raygenGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - raygenGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(raygenGroupCI); + std::vector shaderStages; - VkRayTracingShaderGroupCreateInfoKHR missGroupCI{}; - missGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - missGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - missGroupCI.generalShader = shaderIndexMiss; - missGroupCI.closestHitShader = VK_SHADER_UNUSED_KHR; - missGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - missGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(missGroupCI); - // Second miss group for the shadow miss shader - missGroupCI.generalShader = shaderIndexShadowMiss; - shaderGroups.push_back(missGroupCI); + // Ray generation group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingshadows/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(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); + } - VkRayTracingShaderGroupCreateInfoKHR closesHitGroupCI{}; - closesHitGroupCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - closesHitGroupCI.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - closesHitGroupCI.generalShader = VK_SHADER_UNUSED_KHR; - closesHitGroupCI.closestHitShader = shaderIndexClosestHit; - closesHitGroupCI.anyHitShader = VK_SHADER_UNUSED_KHR; - closesHitGroupCI.intersectionShader = VK_SHADER_UNUSED_KHR; - shaderGroups.push_back(closesHitGroupCI); + // Miss group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingshadows/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(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); + // Second shader for shadows + shaderStages.push_back(loadShader(getShadersPath() + "raytracingshadows/shadow.rmiss.spv", VK_SHADER_STAGE_MISS_BIT_KHR)); + shaderGroup.generalShader = static_cast(shaderStages.size()) - 1; + shaderGroups.push_back(shaderGroup); + } - VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI{}; - rayTracingPipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + // Closest hit group + { + shaderStages.push_back(loadShader(getShadersPath() + "raytracingshadows/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(shaderStages.size()) - 1; + shaderGroup.anyHitShader = VK_SHADER_UNUSED_KHR; + shaderGroup.intersectionShader = VK_SHADER_UNUSED_KHR; + shaderGroups.push_back(shaderGroup); + } + + VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI = vks::initializers::rayTracingPipelineCreateInfoKHR(); rayTracingPipelineCI.stageCount = static_cast(shaderStages.size()); rayTracingPipelineCI.pStages = shaderStages.data(); rayTracingPipelineCI.groupCount = static_cast(shaderGroups.size()); rayTracingPipelineCI.pGroups = shaderGroups.data(); - rayTracingPipelineCI.maxRecursionDepth = 2; + rayTracingPipelineCI.maxPipelineRayRecursionDepth = 2; rayTracingPipelineCI.layout = pipelineLayout; - rayTracingPipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; - VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline)); + VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline)); } /* @@ -683,12 +453,8 @@ public: */ void handleResize() { - // Delete allocated resources - vkDestroyImageView(device, storageImage.view, nullptr); - vkDestroyImage(device, storageImage.image, nullptr); - vkFreeMemory(device, storageImage.memory, nullptr); // Recreate image - createStorageImage(); + createStorageImage(swapChain.colorFormat, { width, height, 1 }); // 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); @@ -719,37 +485,13 @@ public: 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); - /* - Setup the buffer regions pointing to the shader groups in the shader binding table - */ - const VkDeviceSize sbtSize = rayTracingProperties.shaderGroupBaseAlignment * (VkDeviceSize)shaderGroups.size(); - - VkStridedBufferRegionKHR raygenShaderSBTEntry{}; - raygenShaderSBTEntry.buffer = shaderBindingTable.buffer; - raygenShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_RAYGEN_GROUP); - raygenShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - raygenShaderSBTEntry.size = sbtSize; - - VkStridedBufferRegionKHR missShaderSBTEntry{}; - missShaderSBTEntry.buffer = shaderBindingTable.buffer; - missShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_MISS_GROUP); - missShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - missShaderSBTEntry.size = sbtSize; - - VkStridedBufferRegionKHR hitShaderSBTEntry{}; - hitShaderSBTEntry.buffer = shaderBindingTable.buffer; - hitShaderSBTEntry.offset = static_cast(rayTracingProperties.shaderGroupBaseAlignment * INDEX_CLOSEST_HIT_GROUP); - hitShaderSBTEntry.stride = rayTracingProperties.shaderGroupBaseAlignment; - hitShaderSBTEntry.size = sbtSize; - - VkStridedBufferRegionKHR callableShaderSBTEntry{}; - + VkStridedDeviceAddressRegionKHR emptySbtEntry = {}; vkCmdTraceRaysKHR( drawCmdBuffers[i], - &raygenShaderSBTEntry, - &missShaderSBTEntry, - &hitShaderSBTEntry, - &callableShaderSBTEntry, + &shaderBindingTables.raygen.stridedDeviceAddressRegion, + &shaderBindingTables.miss.stridedDeviceAddressRegion, + &shaderBindingTables.hit.stridedDeviceAddressRegion, + &emptySbtEntry, width, height, 1); @@ -818,52 +560,29 @@ public: enabledBufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; enabledBufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE; - enabledRayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR; - enabledRayTracingFeatures.rayTracing = VK_TRUE; - enabledRayTracingFeatures.pNext = &enabledBufferDeviceAddresFeatures; + enabledRayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + enabledRayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE; + enabledRayTracingPipelineFeatures.pNext = &enabledBufferDeviceAddresFeatures; - deviceCreatepNextChain = &enabledRayTracingFeatures; + enabledAccelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + enabledAccelerationStructureFeatures.accelerationStructure = VK_TRUE; + enabledAccelerationStructureFeatures.pNext = &enabledRayTracingPipelineFeatures; + + deviceCreatepNextChain = &enabledAccelerationStructureFeatures; } void prepare() { - VulkanExampleBase::prepare(); - - // Query the ray tracing properties of the current implementation, we will need them later on - rayTracingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR; - VkPhysicalDeviceProperties2 deviceProps2{}; - deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - deviceProps2.pNext = &rayTracingProperties; - vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProps2); - - // Query the ray tracing properties of the current implementation, we will need them later on - rayTracingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR; - VkPhysicalDeviceFeatures2 deviceFeatures2{}; - deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - deviceFeatures2.pNext = &rayTracingFeatures; - vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2); - - // Get the function pointers required for ray tracing - vkGetBufferDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR")); - vkBindAccelerationStructureMemoryKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBindAccelerationStructureMemoryKHR")); - vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR")); - vkDestroyAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR")); - vkGetAccelerationStructureMemoryRequirementsKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureMemoryRequirementsKHR")); - vkCmdBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructureKHR")); - vkBuildAccelerationStructureKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructureKHR")); - vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR")); - vkCmdTraceRaysKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR")); - vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR")); - vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR")); + VulkanRaytracingSample::prepare(); // Create the acceleration structures used to render the ray traced scene createBottomLevelAccelerationStructure(); createTopLevelAccelerationStructure(); - createStorageImage(); + createStorageImage(swapChain.colorFormat, { width, height, 1 }); createUniformBuffer(); createRayTracingPipeline(); - createShaderBindingTable(); + createShaderBindingTables(); createDescriptorSets(); buildCommandBuffers(); prepared = true;