Using Vulkan C API
This commit is contained in:
parent
b3e6d84807
commit
e642e9dc3a
83 changed files with 8015 additions and 8163 deletions
|
|
@ -25,14 +25,12 @@
|
|||
#include "nvh/alignment.hpp"
|
||||
#include "nvvk/shaders_vk.hpp"
|
||||
#include "obj_loader.h"
|
||||
#include "nvvk/buffers_vk.hpp"
|
||||
|
||||
extern std::vector<std::string> defaultSearchPaths;
|
||||
|
||||
|
||||
void Raytracer::setup(const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
nvvk::ResourceAllocator* allocator,
|
||||
uint32_t queueFamily)
|
||||
void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
||||
{
|
||||
m_device = device;
|
||||
m_physicalDevice = physicalDevice;
|
||||
|
|
@ -40,12 +38,11 @@ void Raytracer::setup(const vk::Device& device,
|
|||
m_graphicsQueueIndex = queueFamily;
|
||||
|
||||
// Requesting ray tracing properties
|
||||
auto properties =
|
||||
m_physicalDevice.getProperties2<vk::PhysicalDeviceProperties2,
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
m_rtProperties = properties.get<vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>();
|
||||
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
||||
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
prop2.pNext = &m_rtProperties;
|
||||
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
||||
|
||||
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
||||
m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties);
|
||||
m_debug.setup(device);
|
||||
}
|
||||
|
|
@ -55,10 +52,10 @@ void Raytracer::destroy()
|
|||
{
|
||||
m_sbtWrapper.destroy();
|
||||
m_rtBuilder.destroy();
|
||||
m_device.destroy(m_rtDescPool);
|
||||
m_device.destroy(m_rtDescSetLayout);
|
||||
m_device.destroy(m_rtPipeline);
|
||||
m_device.destroy(m_rtPipelineLayout);
|
||||
vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
|
||||
vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
|
||||
m_alloc->destroy(m_rtSBTBuffer);
|
||||
}
|
||||
|
||||
|
|
@ -68,30 +65,30 @@ void Raytracer::destroy()
|
|||
auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
||||
{
|
||||
// Building part
|
||||
vk::DeviceAddress vertexAddress = m_device.getBufferAddress({model.vertexBuffer.buffer});
|
||||
vk::DeviceAddress indexAddress = m_device.getBufferAddress({model.indexBuffer.buffer});
|
||||
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
||||
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
||||
|
||||
vk::AccelerationStructureGeometryTrianglesDataKHR triangles;
|
||||
triangles.setVertexFormat(vk::Format::eR32G32B32Sfloat);
|
||||
triangles.setVertexData(vertexAddress);
|
||||
triangles.setVertexStride(sizeof(VertexObj));
|
||||
triangles.setIndexType(vk::IndexType::eUint32);
|
||||
triangles.setIndexData(indexAddress);
|
||||
triangles.setTransformData({});
|
||||
triangles.setMaxVertex(model.nbVertices);
|
||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
||||
triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
triangles.vertexData.deviceAddress = vertexAddress;
|
||||
triangles.vertexStride = sizeof(VertexObj);
|
||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
triangles.indexData.deviceAddress = indexAddress;
|
||||
triangles.transformData = {};
|
||||
triangles.maxVertex = model.nbVertices;
|
||||
|
||||
// Setting up the build info of the acceleration
|
||||
vk::AccelerationStructureGeometryKHR asGeom;
|
||||
asGeom.setGeometryType(vk::GeometryTypeKHR::eTriangles);
|
||||
asGeom.setFlags(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation); // For AnyHit
|
||||
asGeom.geometry.setTriangles(triangles);
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
|
||||
asGeom.geometry.triangles = triangles;
|
||||
|
||||
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(model.nbIndices / 3); // Nb triangles
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = model.nbIndices / 3; // Nb triangles
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||
input.asGeometry.emplace_back(asGeom);
|
||||
|
|
@ -105,11 +102,11 @@ auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
|||
//
|
||||
auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
||||
{
|
||||
vk::DeviceAddress dataAddress = m_device.getBufferAddress({implicitObj.implBuf.buffer});
|
||||
VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer);
|
||||
|
||||
vk::AccelerationStructureGeometryAabbsDataKHR aabbs;
|
||||
aabbs.setData(dataAddress);
|
||||
aabbs.setStride(sizeof(ObjImplicit));
|
||||
VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
|
||||
aabbs.data.deviceAddress = dataAddress;
|
||||
aabbs.stride = sizeof(ObjImplicit);
|
||||
|
||||
// Setting up the build info of the acceleration
|
||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
||||
|
|
@ -118,11 +115,11 @@ auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
|||
asGeom.geometry.aabbs = aabbs;
|
||||
|
||||
|
||||
vk::AccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.setFirstVertex(0);
|
||||
offset.setPrimitiveCount(static_cast<uint32_t>(implicitObj.objImpl.size())); // Nb aabb
|
||||
offset.setPrimitiveOffset(0);
|
||||
offset.setTransformOffset(0);
|
||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
||||
offset.firstVertex = 0;
|
||||
offset.primitiveCount = static_cast<uint32_t>(implicitObj.objImpl.size()); // Nb aabb
|
||||
offset.primitiveOffset = 0;
|
||||
offset.transformOffset = 0;
|
||||
|
||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
||||
input.asGeometry.emplace_back(asGeom);
|
||||
|
|
@ -153,8 +150,8 @@ void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& imp
|
|||
}
|
||||
|
||||
|
||||
m_rtBuilder.buildBlas(allBlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace
|
||||
| vk::BuildAccelerationStructureFlagBitsKHR::eAllowCompaction);
|
||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR
|
||||
| VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
|
||||
}
|
||||
|
||||
void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj)
|
||||
|
|
@ -176,46 +173,48 @@ void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst&
|
|||
if(!implicitObj.objImpl.empty())
|
||||
{
|
||||
nvvk::RaytracingBuilderKHR::Instance rayInst;
|
||||
rayInst.transform = implicitObj.transform; // Position of the instance
|
||||
rayInst.instanceCustomId =
|
||||
static_cast<uint32_t>(implicitObj.blasId); // Same for material index
|
||||
rayInst.blasId = static_cast<uint32_t>(implicitObj.blasId);
|
||||
rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one)
|
||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
rayInst.transform = implicitObj.transform; // Position of the instance
|
||||
rayInst.instanceCustomId = static_cast<uint32_t>(implicitObj.blasId); // Same for material index
|
||||
rayInst.blasId = static_cast<uint32_t>(implicitObj.blasId);
|
||||
rayInst.hitGroupId = 1; // We will use the same hit group for all objects (the second one)
|
||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
tlas.emplace_back(rayInst);
|
||||
}
|
||||
|
||||
m_rtBuilder.buildTlas(tlas, vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace);
|
||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// This descriptor set holds the Acceleration structure and the output image
|
||||
//
|
||||
void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage)
|
||||
void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
|
||||
{
|
||||
using vkDT = vk::DescriptorType;
|
||||
using vkSS = vk::ShaderStageFlagBits;
|
||||
using vkDSLB = vk::DescriptorSetLayoutBinding;
|
||||
using vkDSLB = VkDescriptorSetLayoutBinding;
|
||||
|
||||
m_rtDescSetLayoutBind.addBinding(vkDSLB(0, vkDT::eAccelerationStructureKHR, 1,
|
||||
vkSS::eRaygenKHR | vkSS::eClosestHitKHR)); // TLAS
|
||||
m_rtDescSetLayoutBind.addBinding(
|
||||
vkDSLB(1, vkDT::eStorageImage, 1, vkSS::eRaygenKHR)); // Output image
|
||||
m_rtDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
|
||||
m_rtDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
|
||||
|
||||
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
||||
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
||||
m_rtDescSet = m_device.allocateDescriptorSets({m_rtDescPool, 1, &m_rtDescSetLayout})[0];
|
||||
|
||||
vk::AccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
vk::WriteDescriptorSetAccelerationStructureKHR descASInfo;
|
||||
descASInfo.setAccelerationStructureCount(1);
|
||||
descASInfo.setPAccelerationStructures(&tlas);
|
||||
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
|
||||
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||
allocateInfo.descriptorPool = m_rtDescPool;
|
||||
allocateInfo.descriptorSetCount = 1;
|
||||
allocateInfo.pSetLayouts = &m_rtDescSetLayout;
|
||||
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
|
||||
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
||||
descASInfo.accelerationStructureCount = 1;
|
||||
descASInfo.pAccelerationStructures = &tlas;
|
||||
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
||||
|
||||
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 0, &descASInfo));
|
||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo));
|
||||
m_device.updateDescriptorSets(static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -223,169 +222,188 @@ void Raytracer::createRtDescriptorSet(const vk::ImageView& outputImage)
|
|||
// Writes the output image to the descriptor set
|
||||
// - Required when changing resolution
|
||||
//
|
||||
void Raytracer::updateRtDescriptorSet(const vk::ImageView& outputImage)
|
||||
void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage)
|
||||
{
|
||||
using vkDT = vk::DescriptorType;
|
||||
|
||||
// (1) Output buffer
|
||||
vk::DescriptorImageInfo imageInfo{{}, outputImage, vk::ImageLayout::eGeneral};
|
||||
vk::WriteDescriptorSet wds{m_rtDescSet, 1, 0, 1, vkDT::eStorageImage, &imageInfo};
|
||||
m_device.updateDescriptorSets(wds, nullptr);
|
||||
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
||||
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, 1, &imageInfo);
|
||||
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
|
||||
//
|
||||
void Raytracer::createRtPipeline(vk::DescriptorSetLayout& sceneDescLayout)
|
||||
void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout)
|
||||
{
|
||||
vk::ShaderModule raygenSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule missSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
||||
|
||||
// The second miss shader is invoked when a shadow ray misses the geometry. It
|
||||
// simply indicates that no occlusion has been found
|
||||
vk::ShaderModule shadowmissSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||
enum StageIndices
|
||||
{
|
||||
eRaygen,
|
||||
eMiss,
|
||||
eMiss2,
|
||||
eClosestHit,
|
||||
eAnyHit,
|
||||
eClosestHit1,
|
||||
eAnyHit1,
|
||||
eIntersect,
|
||||
eCall0,
|
||||
eCall1,
|
||||
eCall2,
|
||||
eShaderGroupCount
|
||||
};
|
||||
|
||||
// All stages
|
||||
std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
|
||||
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
||||
stage.pName = "main"; // All the same entry point
|
||||
// Raygen
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||
stages[eRaygen] = stage;
|
||||
// Miss
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||
stages[eMiss] = stage;
|
||||
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
|
||||
stage.module =
|
||||
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||
stages[eMiss2] = stage;
|
||||
// Hit Group - Closest Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
stages[eClosestHit] = stage;
|
||||
// Hit Group - Closest Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||
stages[eAnyHit] = stage;
|
||||
// Hit Group - 1
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
stages[eClosestHit1] = stage;
|
||||
// Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
||||
stages[eAnyHit1] = stage;
|
||||
// Hit
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
|
||||
stages[eIntersect] = stage;
|
||||
|
||||
// Call0
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||
stages[eCall0] = stage;
|
||||
// Call1
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||
stages[eCall1] = stage;
|
||||
// Call2
|
||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
||||
stages[eCall2] = stage;
|
||||
|
||||
|
||||
std::vector<vk::PipelineShaderStageCreateInfo> stages;
|
||||
// Shader groups
|
||||
VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
|
||||
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||
|
||||
// Raygen
|
||||
vk::RayTracingShaderGroupCreateInfoKHR rg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
rg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eRaygenKHR, raygenSM, "main"});
|
||||
m_rtShaderGroups.push_back(rg); // 0
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eRaygen;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Miss
|
||||
vk::RayTracingShaderGroupCreateInfoKHR mg{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, missSM, "main"});
|
||||
m_rtShaderGroups.push_back(mg); // 1
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eMiss;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Shadow Miss
|
||||
mg.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eMissKHR, shadowmissSM, "main"});
|
||||
m_rtShaderGroups.push_back(mg); // 2
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.generalShader = eMiss2;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Hit Group0 - Closest Hit + AnyHit
|
||||
vk::ShaderModule chitSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule ahitSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
||||
// closest hit shader
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit;
|
||||
group.anyHitShader = eAnyHit;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chitSM, "main"});
|
||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahitSM, "main"});
|
||||
m_rtShaderGroups.push_back(hg); // 3
|
||||
|
||||
|
||||
// Hit Group1 - Closest Hit + Intersection (procedural)
|
||||
vk::ShaderModule chit2SM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule ahit2SM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule rintSM = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
||||
{
|
||||
vk::RayTracingShaderGroupCreateInfoKHR hg{vk::RayTracingShaderGroupTypeKHR::eProceduralHitGroup,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
hg.setClosestHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eClosestHitKHR, chit2SM, "main"});
|
||||
hg.setAnyHitShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eAnyHitKHR, ahit2SM, "main"});
|
||||
hg.setIntersectionShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eIntersectionKHR, rintSM, "main"});
|
||||
m_rtShaderGroups.push_back(hg); // 4
|
||||
}
|
||||
// closest hit shader
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
|
||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
||||
group.closestHitShader = eClosestHit1;
|
||||
group.anyHitShader = eAnyHit1;
|
||||
group.intersectionShader = eIntersect;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
// Callable shaders
|
||||
vk::RayTracingShaderGroupCreateInfoKHR callGroup{vk::RayTracingShaderGroupTypeKHR::eGeneral,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR,
|
||||
VK_SHADER_UNUSED_KHR, VK_SHADER_UNUSED_KHR};
|
||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||
group.generalShader = eCall0;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
group.generalShader = eCall1;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
group.generalShader = eCall2;
|
||||
m_rtShaderGroups.push_back(group);
|
||||
|
||||
vk::ShaderModule call0 = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule call1 = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
||||
vk::ShaderModule call2 = nvvk::createShaderModule(
|
||||
m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
||||
|
||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call0, "main"});
|
||||
m_rtShaderGroups.push_back(callGroup); // 5
|
||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call1, "main"});
|
||||
m_rtShaderGroups.push_back(callGroup); // 6
|
||||
callGroup.setGeneralShader(static_cast<uint32_t>(stages.size()));
|
||||
stages.push_back({{}, vk::ShaderStageFlagBits::eCallableKHR, call2, "main"});
|
||||
m_rtShaderGroups.push_back(callGroup); //7
|
||||
|
||||
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
|
||||
|
||||
// Push constant: we want to be able to update constants used by the shaders
|
||||
vk::PushConstantRange pushConstant{vk::ShaderStageFlagBits::eRaygenKHR
|
||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
||||
| vk::ShaderStageFlagBits::eMissKHR
|
||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
||||
0, sizeof(RtPushConstants)};
|
||||
pipelineLayoutCreateInfo.setPushConstantRangeCount(1);
|
||||
pipelineLayoutCreateInfo.setPPushConstantRanges(&pushConstant);
|
||||
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
|
||||
| VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
||||
0, sizeof(RtPushConstants)};
|
||||
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
|
||||
|
||||
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
||||
std::vector<vk::DescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
||||
pipelineLayoutCreateInfo.setSetLayoutCount(static_cast<uint32_t>(rtDescSetLayouts.size()));
|
||||
pipelineLayoutCreateInfo.setPSetLayouts(rtDescSetLayouts.data());
|
||||
std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
||||
pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
|
||||
pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
|
||||
|
||||
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
|
||||
|
||||
m_rtPipelineLayout = m_device.createPipelineLayout(pipelineLayoutCreateInfo);
|
||||
|
||||
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
||||
vk::RayTracingPipelineCreateInfoKHR rayPipelineInfo;
|
||||
rayPipelineInfo.setStageCount(static_cast<uint32_t>(stages.size())); // Stages are shaders
|
||||
rayPipelineInfo.setPStages(stages.data());
|
||||
VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
||||
rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
|
||||
rayPipelineInfo.pStages = stages.data();
|
||||
|
||||
rayPipelineInfo.setGroupCount(static_cast<uint32_t>(
|
||||
m_rtShaderGroups.size())); // 1-raygen, n-miss, n-(hit[+anyhit+intersect])
|
||||
rayPipelineInfo.setPGroups(m_rtShaderGroups.data());
|
||||
rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
|
||||
rayPipelineInfo.pGroups = m_rtShaderGroups.data();
|
||||
|
||||
rayPipelineInfo.setMaxPipelineRayRecursionDepth(2); // Ray depth
|
||||
rayPipelineInfo.setLayout(m_rtPipelineLayout);
|
||||
// The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
|
||||
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
|
||||
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
|
||||
// in the ray generation to avoid deep recursion.
|
||||
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
||||
rayPipelineInfo.layout = m_rtPipelineLayout;
|
||||
|
||||
m_rtPipeline = m_device.createRayTracingPipelineKHR({}, {}, rayPipelineInfo).value;
|
||||
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
||||
|
||||
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
||||
|
||||
m_device.destroy(raygenSM);
|
||||
m_device.destroy(missSM);
|
||||
m_device.destroy(shadowmissSM);
|
||||
m_device.destroy(chitSM);
|
||||
m_device.destroy(ahitSM);
|
||||
m_device.destroy(chit2SM);
|
||||
m_device.destroy(ahit2SM);
|
||||
m_device.destroy(rintSM);
|
||||
m_device.destroy(call0);
|
||||
m_device.destroy(call1);
|
||||
m_device.destroy(call2);
|
||||
|
||||
for(auto& s : stages)
|
||||
vkDestroyShaderModule(m_device, s.module, nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Ray Tracing the scene
|
||||
//
|
||||
void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
|
||||
const nvmath::vec4f& clearColor,
|
||||
vk::DescriptorSet& sceneDescSet,
|
||||
vk::Extent2D& size,
|
||||
ObjPushConstants& sceneConstants)
|
||||
void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
|
||||
const nvmath::vec4f& clearColor,
|
||||
VkDescriptorSet& sceneDescSet,
|
||||
VkExtent2D& size,
|
||||
ObjPushConstants& sceneConstants)
|
||||
{
|
||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
||||
// Initializing push constant values
|
||||
|
|
@ -398,19 +416,19 @@ void Raytracer::raytrace(const vk::CommandBuffer& cmdBuf,
|
|||
m_rtPushConstants.lightType = sceneConstants.lightType;
|
||||
m_rtPushConstants.frame = sceneConstants.frame;
|
||||
|
||||
cmdBuf.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipeline);
|
||||
cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingKHR, m_rtPipelineLayout, 0,
|
||||
{m_rtDescSet, sceneDescSet}, {});
|
||||
cmdBuf.pushConstants<RtPushConstants>(m_rtPipelineLayout,
|
||||
vk::ShaderStageFlagBits::eRaygenKHR
|
||||
| vk::ShaderStageFlagBits::eClosestHitKHR
|
||||
| vk::ShaderStageFlagBits::eMissKHR
|
||||
| vk::ShaderStageFlagBits::eCallableKHR,
|
||||
0, m_rtPushConstants);
|
||||
|
||||
std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet};
|
||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
|
||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
|
||||
(uint32_t)descSets.size(), descSets.data(), 0, nullptr);
|
||||
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
|
||||
| VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
||||
0, sizeof(RtPushConstants), &m_rtPushConstants);
|
||||
|
||||
|
||||
auto regions = m_sbtWrapper.getRegions();
|
||||
cmdBuf.traceRaysKHR(regions[0], regions[1], regions[2], regions[3], size.width, size.height, 1);
|
||||
auto& regions = m_sbtWrapper.getRegions();
|
||||
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1);
|
||||
|
||||
m_debug.endLabel(cmdBuf);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue