ray_tracing_gltf/hello_vulkan.cpp
void HelloVulkan::createRtPipeline()
{
  enum StageIndices
  {
    eRaygen,
    eMiss,
    eMiss2,
    eClosestHit,
    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/pathtrace.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/pathtrace.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/pathtrace.rchit.spv", true, defaultSearchPaths, true));
  stage.stage         = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
  stages[eClosestHit] = stage;


  // 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
  group.type          = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
  group.generalShader = eRaygen;
  m_rtShaderGroups.push_back(group);

  // Miss
  group.type          = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
  group.generalShader = eMiss;
  m_rtShaderGroups.push_back(group);

  // Shadow Miss
  group.type          = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
  group.generalShader = eMiss2;
  m_rtShaderGroups.push_back(group);

  // closest hit shader
  group.type             = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
  group.generalShader    = VK_SHADER_UNUSED_KHR;
  group.closestHitShader = eClosestHit;
  m_rtShaderGroups.push_back(group);


  // Push constant: we want to be able to update constants used by the shaders
  VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
                                   0, sizeof(PushConstantRay)};


  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<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout};
  pipelineLayoutCreateInfo.setLayoutCount             = static_cast<uint32_t>(rtDescSetLayouts.size());
  pipelineLayoutCreateInfo.pSetLayouts                = rtDescSetLayouts.data();

  vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);


  // Assemble the shader stages and recursion depth info into the ray tracing pipeline
  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();

  // In this case, m_rtShaderGroups.size() == 4: we have one raygen group,
  // two miss shader groups, and one hit group.
  rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
  rayPipelineInfo.pGroups    = m_rtShaderGroups.data();

  // 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;

  vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);


  // Creating the SBT
  m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);


  for(auto& s : stages)
    vkDestroyShaderModule(m_device, s.module, nullptr);
}
//--------------------------------------------------------------------------------------------------
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
//
Pipeline for the ray tracer: all shaders, raygen, chit, miss
Pipeline for the ray tracer : all shaders raygen chit miss
void HelloVulkan::createRtPipeline()
{
  enum StageIndices
  {
    eRaygen,
    eMiss,
    eMiss2,
    eClosestHit,
    eShaderGroupCount
  };
  std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
  VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
  stage.pName = "main";  
  stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pathtrace.rgen.spv", true, defaultSearchPaths, true));
  stage.stage     = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
  stages[eRaygen] = stage;
  stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pathtrace.rmiss.spv", true, defaultSearchPaths, true));
  stage.stage   = VK_SHADER_STAGE_MISS_BIT_KHR;
  stages[eMiss] = stage;
  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;
  stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/pathtrace.rchit.spv", true, defaultSearchPaths, true));
  stage.stage         = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
  stages[eClosestHit] = stage;
  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;
  group.type          = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
  group.generalShader = eRaygen;
  m_rtShaderGroups.push_back(group);
  group.type          = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
  group.generalShader = eMiss;
  m_rtShaderGroups.push_back(group);
  group.type          = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
  group.generalShader = eMiss2;
  m_rtShaderGroups.push_back(group);
  group.type             = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
  group.generalShader    = VK_SHADER_UNUSED_KHR;
  group.closestHitShader = eClosestHit;
  m_rtShaderGroups.push_back(group);
  VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
                                   0, sizeof(PushConstantRay)};
  VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
  pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
  pipelineLayoutCreateInfo.pPushConstantRanges    = &pushConstant;
  std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout};
  pipelineLayoutCreateInfo.setLayoutCount             = static_cast<uint32_t>(rtDescSetLayouts.size());
  pipelineLayoutCreateInfo.pSetLayouts                = rtDescSetLayouts.data();
  vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
  VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
  rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size());  
  rayPipelineInfo.pStages    = stages.data();
  rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
  rayPipelineInfo.pGroups    = m_rtShaderGroups.data();
  rayPipelineInfo.maxPipelineRayRecursionDepth = 2;  
  rayPipelineInfo.layout                       = m_rtPipelineLayout;
  vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
  m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
  for(auto& s : stages)
    vkDestroyShaderModule(m_device, s.module, nullptr);
}
void HelloVulkan :: createRtPipeline ( ) { enum StageIndices { eRaygen , eMiss , eMiss2 , eClosestHit , eShaderGroupCount } ; std :: array < VkPipelineShaderStageCreateInfo , eShaderGroupCount > stages { } ; VkPipelineShaderStageCreateInfo stage { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO } ; stage . pName = " " ; stage . module = nvvk :: createShaderModule ( m_device , nvh :: loadFile ( " " , true , defaultSearchPaths , true ) ) ; stage . stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR ; stages [ eRaygen ] = stage ; stage . module = nvvk :: createShaderModule ( m_device , nvh :: loadFile ( " " , true , defaultSearchPaths , true ) ) ; stage . stage = VK_SHADER_STAGE_MISS_BIT_KHR ; stages [ eMiss ] = stage ; stage . module = nvvk :: createShaderModule ( m_device , nvh :: loadFile ( " " , true , defaultSearchPaths , true ) ) ; stage . stage = VK_SHADER_STAGE_MISS_BIT_KHR ; stages [ eMiss2 ] = stage ; stage . module = nvvk :: createShaderModule ( m_device , nvh :: loadFile ( " " , true , defaultSearchPaths , true ) ) ; stage . stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ; stages [ eClosestHit ] = stage ; 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 ; group . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR ; group . generalShader = eRaygen ; m_rtShaderGroups . push_back ( group ) ; group . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR ; group . generalShader = eMiss ; m_rtShaderGroups . push_back ( group ) ; group . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR ; group . generalShader = eMiss2 ; m_rtShaderGroups . push_back ( group ) ; group . type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR ; group . generalShader = VK_SHADER_UNUSED_KHR ; group . closestHitShader = eClosestHit ; m_rtShaderGroups . push_back ( group ) ; VkPushConstantRange pushConstant { VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR , 0 , sizeof ( PushConstantRay ) } ; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO } ; pipelineLayoutCreateInfo . pushConstantRangeCount = 1 ; pipelineLayoutCreateInfo . pPushConstantRanges = & pushConstant ; std :: vector < VkDescriptorSetLayout > rtDescSetLayouts = { m_rtDescSetLayout , m_descSetLayout } ; pipelineLayoutCreateInfo . setLayoutCount = static_cast < uint32_t > ( rtDescSetLayouts . size ( ) ) ; pipelineLayoutCreateInfo . pSetLayouts = rtDescSetLayouts . data ( ) ; vkCreatePipelineLayout ( m_device , & pipelineLayoutCreateInfo , nullptr , & m_rtPipelineLayout ) ; VkRayTracingPipelineCreateInfoKHR rayPipelineInfo { VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR } ; rayPipelineInfo . stageCount = static_cast < uint32_t > ( stages . size ( ) ) ; rayPipelineInfo . pStages = stages . data ( ) ; rayPipelineInfo . groupCount = static_cast < uint32_t > ( m_rtShaderGroups . size ( ) ) ; rayPipelineInfo . pGroups = m_rtShaderGroups . data ( ) ; rayPipelineInfo . maxPipelineRayRecursionDepth = 2 ; rayPipelineInfo . layout = m_rtPipelineLayout ; vkCreateRayTracingPipelinesKHR ( m_device , { } , { } , 1 , & rayPipelineInfo , nullptr , & m_rtPipeline ) ; m_sbtWrapper . create ( m_rtPipeline , rayPipelineInfo ) ; for ( auto & s : stages ) vkDestroyShaderModule ( m_device , s . module , nullptr ) ; }
Pipeline for the ray tracer: all shaders, raygen, chit, miss
Pipeline for the ray tracer : all shaders raygen chit miss
// All stages // All the same entry point // Raygen // Miss // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found // Hit Group - Closest Hit // Shader groups // Raygen // Miss // Shadow Miss // closest hit shader // Push constant: we want to be able to update constants used by the shaders // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline // Assemble the shader stages and recursion depth info into the ray tracing pipeline // Stages are shaders // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, // two miss shader groups, and one hit group. // 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. // Ray depth // Creating the SBT