blob: d406354d9b1dbc416a8f68999df32e1e22ec8198 [file] [log] [blame]
/*
* Copyright (c) 2024-2025 Valve Corporation
* Copyright (c) 2024-2025 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#pragma once
#include "binding.h"
#include "descriptor_helper.h"
#include "shader_helper.h"
#include <optional>
namespace vkt {
// acceleration structure
namespace as {
// Helper classes to create instances of:
// - VkAccelerationStructureGeometryKHR
// - VkAccelerationStructureCreateInfoKHR
// - VkAccelerationStructureBuildGeometryInfoKHR
// The vkt::as::blueprint namespace (bottom of file) contains functions to readily create a valid instance of those classes.
// Those instances are typically modified using the available public methods.
// When done with modifications, call the Build() method to build the internal Vulkan objects.
// Access them using relevant methods, eg: handle(), GetVkObj()...
// 3 types of geometry handled: Triangle, AABB and VkAccelerationStructureInstanceKHR (used in top level acceleration structures)
// Those objects can be managed on the device, using the ***Device*** methods,
// or on the host using the ***Host*** methods
class GeometryKHR {
public:
enum class Type { Triangle, AABB, Instance, Spheres, LSSpheres, _INTERNAL_UNSPECIFIED };
struct Triangles {
vkt::Buffer device_vertex_buffer;
std::unique_ptr<float[]> host_vertex_buffer;
vkt::Buffer device_index_buffer;
std::unique_ptr<uint32_t[]> host_index_buffer;
vkt::Buffer device_transform_buffer;
};
struct AABBs {
vkt::Buffer device_buffer;
std::unique_ptr<VkAabbPositionsKHR[]> host_buffer;
};
struct Instances {
std::vector<VkAccelerationStructureInstanceKHR> vk_instances{};
// Used to (eventually, no need for host instance) store on device instances
vkt::Buffer buffer;
};
struct Spheres {
vkt::Buffer device_vertex_buffer;
std::unique_ptr<float[]> host_vertex_buffer;
vkt::Buffer device_index_buffer;
std::unique_ptr<uint32_t[]> host_index_buffer;
vkt::Buffer device_radius_buffer;
std::unique_ptr<float[]> host_radius_buffer;
std::shared_ptr<VkAccelerationStructureGeometrySpheresDataNV> sphere_geometry_ptr;
};
struct LSSpheres {
vkt::Buffer device_vertex_buffer;
std::unique_ptr<float[]> host_vertex_buffer;
vkt::Buffer device_index_buffer;
std::unique_ptr<uint32_t[]> host_index_buffer;
vkt::Buffer device_radius_buffer;
std::unique_ptr<float[]> host_radius_buffer;
std::shared_ptr<VkAccelerationStructureGeometryLinearSweptSpheresDataNV> sphere_geometry_ptr;
};
~GeometryKHR() = default;
GeometryKHR();
GeometryKHR(const GeometryKHR&) = delete;
GeometryKHR(GeometryKHR&&) = default;
GeometryKHR& operator=(GeometryKHR&&) = default;
GeometryKHR& operator=(const GeometryKHR&) = delete;
// Common methods for all types
GeometryKHR& SetFlags(VkGeometryFlagsKHR flags);
GeometryKHR& SetType(Type type);
GeometryKHR& SetPrimitiveCount(uint32_t primitiveCount);
GeometryKHR& SetStride(VkDeviceSize stride);
// Triangle
GeometryKHR& SetTrianglesDeviceVertexBuffer(vkt::Buffer&& vertex_buffer, uint32_t max_vertex,
VkFormat vertex_format = VK_FORMAT_R32G32B32_SFLOAT,
VkDeviceSize stride = 3 * sizeof(float), VkDeviceSize vertex_buffer_offset = 0);
GeometryKHR& SetTrianglesHostVertexBuffer(std::unique_ptr<float[]>&& vertex_buffer, uint32_t max_vertex,
VkDeviceSize stride = 3 * sizeof(float));
GeometryKHR& SetTrianglesDeviceIndexBuffer(vkt::Buffer&& index_buffer, VkIndexType index_type = VK_INDEX_TYPE_UINT32);
GeometryKHR& SetTrianglesHostIndexBuffer(std::unique_ptr<uint32_t[]> index_buffer);
GeometryKHR& SetTrianglesIndexType(VkIndexType index_type);
GeometryKHR& SetTrianglesVertexFormat(VkFormat vertex_format);
GeometryKHR& SetTrianglesMaxVertex(uint32_t max_vertex);
GeometryKHR& SetTrianglesTransformBuffer(vkt::Buffer&& transform_buffer);
GeometryKHR& SetTrianglesTransformatData(VkDeviceAddress address);
GeometryKHR& SetTrianglesVertexBufferDeviceAddress(VkDeviceAddress address);
GeometryKHR& SetTrianglesIndexBufferDeviceAddress(VkDeviceAddress address);
// AABB
GeometryKHR& SetAABBsDeviceBuffer(vkt::Buffer&& buffer, VkDeviceSize stride = sizeof(VkAabbPositionsKHR));
GeometryKHR& SetAABBsHostBuffer(std::unique_ptr<VkAabbPositionsKHR[]> buffer, VkDeviceSize stride = sizeof(VkAabbPositionsKHR));
GeometryKHR& SetAABBsStride(VkDeviceSize stride);
GeometryKHR& SetAABBsDeviceAddress(VkDeviceAddress address);
// Instance
GeometryKHR& AddInstanceDeviceAccelStructRef(const vkt::Device& device, VkAccelerationStructureKHR blas,
const VkAccelerationStructureInstanceKHR& instance);
// Both the host stored and device stored instances will be updated
void UpdateAccelerationStructureInstance(size_t i, std::function<void(VkAccelerationStructureInstanceKHR&)> f);
GeometryKHR& AddInstanceHostAccelStructRef(VkAccelerationStructureKHR blas);
GeometryKHR& SetInstancesDeviceAddress(VkDeviceAddress address);
GeometryKHR& SetInstanceHostAccelStructRef(VkAccelerationStructureKHR blas, uint32_t instance_i);
GeometryKHR& SetInstanceHostAddress(void* address);
GeometryKHR& SetInstanceShaderBindingTableRecordOffset(uint32_t instance_i, uint32_t instance_sbt_record_offset);
// Spheres
GeometryKHR& SetSpheresVertexFormat(VkFormat vertex_format);
GeometryKHR& SetSpheresRadiusFormat(VkFormat radius_format);
GeometryKHR& SetSpheresDeviceVertexBuffer(vkt::Buffer&& vertex_buffer, VkFormat vertex_format = VK_FORMAT_R32G32B32_SFLOAT,
VkDeviceSize stride = 3 * sizeof(float));
GeometryKHR& SetSpheresDeviceIndexBuffer(vkt::Buffer&& index_buffer, VkIndexType index_type = VK_INDEX_TYPE_UINT32);
GeometryKHR& SetSpheresDeviceRadiusBuffer(vkt::Buffer&& radius_buffer, VkDeviceSize stride = sizeof(float));
GeometryKHR& SetSpheresHostVertexBuffer(std::unique_ptr<float[]>&& vertex_buffer, VkDeviceSize stride = 3 * sizeof(float));
GeometryKHR& SetSpheresHostIndexBuffer(std::unique_ptr<uint32_t[]> index_buffer);
GeometryKHR& SetSpheresHostRadiusBuffer(std::unique_ptr<float[]> radius_buffer, VkDeviceSize stride = sizeof(float));
GeometryKHR& SetSpheresIndexType(VkIndexType index_type);
GeometryKHR& SetSpheresVertexStride(VkDeviceSize stride);
GeometryKHR& SetSpheresRadiusStride(VkDeviceSize stride);
GeometryKHR& SetSpheresIndexAddressZero();
GeometryKHR& SetSpheresVertexAddressZero();
GeometryKHR& SetSpheresRadiusAddressZero();
// LSSpheres
GeometryKHR& SetLSSpheresVertexFormat(VkFormat vertex_format);
GeometryKHR& SetLSSpheresRadiusFormat(VkFormat radius_format);
GeometryKHR& SetLSSpheresDeviceVertexBuffer(vkt::Buffer&& vertex_buffer, VkFormat vertex_format = VK_FORMAT_R32G32B32_SFLOAT,
VkDeviceSize stride = 3 * sizeof(float));
GeometryKHR& SetLSSpheresDeviceIndexBuffer(vkt::Buffer&& index_buffer, VkIndexType index_type = VK_INDEX_TYPE_UINT32);
GeometryKHR& SetLSSpheresDeviceRadiusBuffer(vkt::Buffer&& radius_buffer, VkDeviceSize stride = sizeof(float));
GeometryKHR& SetLSSpheresHostVertexBuffer(std::unique_ptr<float[]>&& vertex_buffer, VkDeviceSize stride = 3 * sizeof(float));
GeometryKHR& SetLSSpheresHostIndexBuffer(std::unique_ptr<uint32_t[]> index_buffer);
GeometryKHR& SetLSSpheresHostRadiusBuffer(std::unique_ptr<float[]> radius_buffer, VkDeviceSize stride = sizeof(float));
GeometryKHR& SetLSSpheresIndexType(VkIndexType index_type);
GeometryKHR& SetLSSpheresVertexStride(VkDeviceSize stride);
GeometryKHR& SetLSSpheresRadiusStride(VkDeviceSize stride);
GeometryKHR& SetLSSpheresIndexingMode(VkRayTracingLssIndexingModeNV index_mode);
GeometryKHR& SetLSSpheresIndexDataNull();
GeometryKHR& SetLSSpheresIndexAddressZero();
GeometryKHR& SetLSSpheresVertexAddressZero();
GeometryKHR& SetLSSpheresRadiusAddressZero();
const auto& GetVkObj() const { return vk_obj_; }
VkAccelerationStructureBuildRangeInfoKHR GetFullBuildRange() const;
const auto& GetTriangles() const { return triangles_; }
const auto& GetAABBs() const { return aabbs_; }
auto& GetInstance() { return instances_; }
VkGeometryFlagsKHR GetFlags() { return vk_obj_.flags; };
private:
VkAccelerationStructureGeometryKHR vk_obj_;
Type type_ = Type::_INTERNAL_UNSPECIFIED;
uint32_t primitive_count_ = 0;
Triangles triangles_;
AABBs aabbs_;
Instances instances_;
Spheres spheres_;
LSSpheres lsspheres_;
};
class AccelerationStructureKHR : public vkt::internal::NonDispHandle<VkAccelerationStructureKHR> {
public:
~AccelerationStructureKHR() { Destroy(); }
AccelerationStructureKHR(const vkt::Device* device);
AccelerationStructureKHR(AccelerationStructureKHR&& rhs) = default;
AccelerationStructureKHR& operator=(AccelerationStructureKHR&&) = default;
AccelerationStructureKHR& operator=(const AccelerationStructureKHR&) = delete;
AccelerationStructureKHR& SetSize(VkDeviceSize size);
AccelerationStructureKHR& SetOffset(VkDeviceSize offset);
AccelerationStructureKHR& SetType(VkAccelerationStructureTypeKHR type);
AccelerationStructureKHR& SetFlags(VkAccelerationStructureCreateFlagsKHR flags);
AccelerationStructureKHR& SetDeviceBuffer(vkt::Buffer&& buffer);
AccelerationStructureKHR& SetDeviceBufferMemoryAllocateFlags(VkMemoryAllocateFlags memory_allocate_flags);
AccelerationStructureKHR& SetDeviceBufferMemoryPropertyFlags(VkMemoryPropertyFlags memory_property_flags);
AccelerationStructureKHR& SetDeviceBufferInitNoMem(bool buffer_init_no_mem);
// Set it to 0 to skip buffer initialization at Build() step
AccelerationStructureKHR& SetBufferUsageFlags(VkBufferUsageFlags usage_flags);
VkDeviceAddress GetBufferDeviceAddress() const;
VkDeviceAddress GetAccelerationStructureDeviceAddress() const;
// Null check is done in BuildGeometryInfoKHR::Build(). Object is build iff it is not null.
void SetNull(bool is_null) { is_null_ = is_null; }
bool IsNull() const { return is_null_; }
void Create();
bool IsBuilt() const { return initialized(); }
void Destroy();
auto& GetBuffer() { return device_buffer_; }
private:
const vkt::Device* device_;
bool is_null_ = false;
VkAccelerationStructureCreateInfoKHR vk_info_;
vkt::Buffer device_buffer_;
VkMemoryAllocateFlags buffer_memory_allocate_flags_{};
VkMemoryPropertyFlags buffer_memory_property_flags_{};
VkBufferUsageFlags buffer_usage_flags_{};
bool buffer_init_no_mem_ = false;
};
class BuildGeometryInfoKHR {
public:
~BuildGeometryInfoKHR() = default;
BuildGeometryInfoKHR(const vkt::Device* device);
BuildGeometryInfoKHR(BuildGeometryInfoKHR&&) = default;
BuildGeometryInfoKHR& operator=(BuildGeometryInfoKHR&& rhs) = default;
BuildGeometryInfoKHR& operator=(const BuildGeometryInfoKHR&) = delete;
BuildGeometryInfoKHR& SetType(VkAccelerationStructureTypeKHR type);
BuildGeometryInfoKHR& SetBuildType(VkAccelerationStructureBuildTypeKHR build_type);
BuildGeometryInfoKHR& SetMode(VkBuildAccelerationStructureModeKHR mode);
BuildGeometryInfoKHR& SetFlags(VkBuildAccelerationStructureFlagsKHR flags);
BuildGeometryInfoKHR& AddFlags(VkBuildAccelerationStructureFlagsKHR flags);
BuildGeometryInfoKHR& SetGeometries(std::vector<GeometryKHR>&& geometries);
BuildGeometryInfoKHR& SetBuildRanges(std::vector<VkAccelerationStructureBuildRangeInfoKHR> build_range_infos);
// Using the same pointers for src and dst is supported
BuildGeometryInfoKHR& SetSrcAS(std::shared_ptr<AccelerationStructureKHR> src_as);
BuildGeometryInfoKHR& SetDstAS(std::shared_ptr<AccelerationStructureKHR> dst_as);
BuildGeometryInfoKHR& SetScratchBuffer(std::shared_ptr<vkt::Buffer> scratch_buffer);
BuildGeometryInfoKHR& SetHostScratchBuffer(std::shared_ptr<std::vector<uint8_t>> host_scratch);
BuildGeometryInfoKHR& SetDeviceScratchOffset(VkDeviceAddress offset);
BuildGeometryInfoKHR& SetDeviceScratchAdditionalFlags(VkBufferUsageFlags additional_flags);
BuildGeometryInfoKHR& SetEnableScratchBuild(bool build_scratch);
// Should be 0 or 1
BuildGeometryInfoKHR& SetInfoCount(uint32_t info_count);
BuildGeometryInfoKHR& SetNullInfos(bool use_null_infos);
BuildGeometryInfoKHR& SetNullGeometries(bool use_null_geometries);
BuildGeometryInfoKHR& SetNullBuildRangeInfos(bool use_null_build_range_infos);
BuildGeometryInfoKHR& SetDeferredOp(VkDeferredOperationKHR deferred_op);
BuildGeometryInfoKHR& SetUpdateDstAccelStructSizeBeforeBuild(bool update_before_build);
BuildGeometryInfoKHR& SetIndirectStride(uint32_t indirect_stride);
BuildGeometryInfoKHR& SetIndirectDeviceAddress(std::optional<VkDeviceAddress> indirect_buffer_address);
// Those functions call Build() on internal resources (geometries, src and dst acceleration structures, scratch buffer),
// then will build/update an acceleration structure.
void BuildCmdBuffer(VkCommandBuffer cmd_buffer);
void BuildCmdBufferIndirect(VkCommandBuffer cmd_buffer);
void BuildHost();
void UpdateDstAccelStructSize();
void SetupBuild(bool is_on_device_build, bool use_ppGeometries = true);
// These will only setup the geometries lists and the pertaining build ranges
void VkCmdBuildAccelerationStructuresKHR(VkCommandBuffer cmd_buffer, bool use_ppGeometries = true);
// TODO - indirect build not fully implemented, only cared about having a valid call at time of writing
void VkCmdBuildAccelerationStructuresIndirectKHR(VkCommandBuffer cmd_buffer);
void VkBuildAccelerationStructuresKHR();
auto& GetInfo() { return vk_info_; }
auto& GetGeometries() { return geometries_; }
auto& GetSrcAS() { return src_as_; }
auto& GetDstAS() { return dst_as_; }
const auto& GetScratchBuffer() const { return device_scratch_; }
VkAccelerationStructureBuildSizesInfoKHR GetSizeInfo(bool use_ppGeometries = true);
std::vector<VkAccelerationStructureBuildRangeInfoKHR> GetBuildRangeInfosFromGeometries();
private:
friend void BuildAccelerationStructuresKHR(VkCommandBuffer cmd_buffer, std::vector<BuildGeometryInfoKHR>& infos);
friend void BuildHostAccelerationStructuresKHR(VkDevice device, std::vector<BuildGeometryInfoKHR>& infos);
const vkt::Device* device_;
uint32_t vk_info_count_ = 1;
bool use_null_infos_ = false;
bool use_null_geometries_ = false;
bool use_null_build_range_infos_ = false;
bool update_dst_as_size_before_build_ = false;
VkAccelerationStructureBuildGeometryInfoKHR vk_info_;
VkAccelerationStructureBuildTypeKHR build_type_;
std::vector<GeometryKHR> geometries_;
std::shared_ptr<AccelerationStructureKHR> src_as_, dst_as_;
bool build_scratch_ = true;
VkDeviceAddress device_scratch_offset_ = 0;
VkBufferUsageFlags device_scratch_additional_flags_ = 0;
std::shared_ptr<vkt::Buffer> device_scratch_;
std::shared_ptr<std::vector<uint8_t>> host_scratch_;
std::unique_ptr<vkt::Buffer> indirect_buffer_;
std::optional<VkDeviceAddress> indirect_buffer_address_{};
uint32_t indirect_stride_ = sizeof(VkAccelerationStructureBuildRangeInfoKHR);
std::vector<VkAccelerationStructureBuildRangeInfoKHR> build_range_infos_;
VkDeferredOperationKHR deferred_op_ = VK_NULL_HANDLE;
};
// Helper functions
void BuildAccelerationStructuresKHR(VkCommandBuffer cmd_buffer, std::vector<BuildGeometryInfoKHR>& infos);
void BuildHostAccelerationStructuresKHR(VkDevice device, std::vector<BuildGeometryInfoKHR>& infos);
// Helper functions providing simple, valid objects.
// Calling Build() on them without further modifications results in a usable and valid Vulkan object.
// Typical usage probably is:
// {
// vkt::as::BuildGeometryInfoKHR as_build_info = BuildGeometryInfoSimpleOnDeviceBottomLevel(*m_device);
//
// // for instance:
// as_build_info.GetDstAS().SetBufferMemoryPropertyFlags(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
// as_build_info.SetFlags(VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
//
// m_command_buffer.Begin();
// as_build_info.BuildCmdBuffer(*m_device, m_command_buffer);
// m_command_buffer.End();
// }
namespace blueprint {
GeometryKHR GeometrySimpleOnDeviceIndexedTriangleInfo(const vkt::Device& device, size_t triangles_count = 1,
VkBufferUsageFlags additional_geometry_buffer_flags = 0);
GeometryKHR GeometrySimpleOnDeviceTriangleInfo(const vkt::Device& device, VkBufferUsageFlags additional_geometry_buffer_flags = 0);
GeometryKHR GeometrySimpleOnHostIndexedTriangleInfo();
// Cube centered at position (0,0,0), 2.0f wide
GeometryKHR GeometryCubeOnDeviceInfo(const vkt::Device& device);
GeometryKHR GeometrySimpleOnDeviceAABBInfo(const vkt::Device& device, VkBufferUsageFlags additional_geometry_buffer_flags = 0);
GeometryKHR GeometrySimpleOnHostAABBInfo();
GeometryKHR GeometrySimpleDeviceInstance(const vkt::Device& device, VkAccelerationStructureKHR device_blas);
GeometryKHR GeometrySimpleOnDeviceSpheresInfo(const vkt::Device& device);
GeometryKHR GeometrySimpleOnHostSpheresInfo();
GeometryKHR GeometrySimpleOnDeviceLSSpheresInfo(const vkt::Device& device);
GeometryKHR GeometrySimpleOnHostLSSpheresInfo();
std::shared_ptr<AccelerationStructureKHR> AccelStructNull(const vkt::Device& device);
std::shared_ptr<AccelerationStructureKHR> AccelStructSimpleOnDeviceBottomLevel(const vkt::Device& device, VkDeviceSize size);
std::shared_ptr<AccelerationStructureKHR> AccelStructSimpleOnHostBottomLevel(const vkt::Device& device, VkDeviceSize size);
std::shared_ptr<AccelerationStructureKHR> AccelStructSimpleOnDeviceTopLevel(const vkt::Device& device, VkDeviceSize size);
BuildGeometryInfoKHR BuildGeometryInfoSimpleOnDeviceBottomLevel(const vkt::Device& device,
GeometryKHR::Type geometry_type = GeometryKHR::Type::Triangle);
BuildGeometryInfoKHR BuildGeometryInfoOnDeviceBottomLevel(const vkt::Device& device, GeometryKHR&& geometry);
BuildGeometryInfoKHR BuildGeometryInfoSimpleOnHostBottomLevel(const vkt::Device& device,
GeometryKHR::Type geometry_type = GeometryKHR::Type::Triangle);
// Create an on device TLAS pointing to one BLAS
// on_device_bottom_level_geometry must have been built previously, and on the device
BuildGeometryInfoKHR BuildGeometryInfoSimpleOnDeviceTopLevel(const vkt::Device& device,
const vkt::as::AccelerationStructureKHR& on_device_blas);
// Create an on host TLAS pointing to one BLAS
// on_host_bottom_level_geometry must have been built previously, and on the host
BuildGeometryInfoKHR BuildGeometryInfoSimpleOnHostTopLevel(const vkt::Device& device,
std::shared_ptr<BuildGeometryInfoKHR> on_host_blas);
// Create and build a top level acceleration structure
BuildGeometryInfoKHR BuildOnDeviceTopLevel(const vkt::Device& device, vkt::Queue& queue, vkt::CommandBuffer& cmd_buffer);
// Build Top Level Acceleration Structure:
// 2 instances of the cube, at different positions
// They are supposed to invoke 2 different closest hist shaders,
// through different instanceShaderBindingTableRecordOffset
// clang-format off
/*
cube instance 2, translation (x = 0, y = 0, z = 50), instanceShaderBindingTableRecordOffset = 1
+----+
| 2 |
+----+
Z
^
| +----+
+---> X | 1 | cube instance 1, translation (x = 50, y = 0, z = 0), instanceShaderBindingTableRecordOffset = 0
+----+
*/
// clang-format on
vkt::as::BuildGeometryInfoKHR GetCubesTLAS(vkt::Device& device, vkt::CommandBuffer& cb, vkt::Queue& queue,
std::shared_ptr<vkt::as::BuildGeometryInfoKHR>& out_cube_blas);
vkt::as::BuildGeometryInfoKHR CreateTLAS(vkt::Device& device, std::vector<vkt::as::GeometryKHR>&& blas_vec);
} // namespace blueprint
} // namespace as
namespace rt {
struct TraceRaysSbt {
VkStridedDeviceAddressRegionKHR ray_gen_sbt{};
VkStridedDeviceAddressRegionKHR miss_sbt{};
VkStridedDeviceAddressRegionKHR hit_sbt{};
VkStridedDeviceAddressRegionKHR callable_sbt{};
};
class Pipeline {
public:
Pipeline(VkLayerTest& test, vkt::Device* device);
~Pipeline();
// Build settings
// --------------
void AddCreateInfoFlags(VkPipelineCreateFlags flags);
void AddCreateInfoFlags2(VkPipelineCreateFlags2 flags);
void InitLibraryInfo(uint32_t max_pipeline_payload_size, bool is_exe_pipeline);
void AddBinding(VkDescriptorType descriptor_type, uint32_t binding, uint32_t descriptor_count = 1);
void CreateDescriptorSet();
void AddDescriptorIndexingBinding(VkDescriptorType descriptor_type, uint32_t binding, VkDescriptorBindingFlags flags = 0,
uint32_t descriptor_count = 1);
void CreateDescriptorIndexingSet();
// *If CreateDescriptorSet() is never called*, this method will hook supplied descriptor set layouts
void SetPipelineSetLayouts(uint32_t set_layout_count, const VkDescriptorSetLayout* set_layouts);
void SetPushConstantRangeSize(uint32_t byte_size);
void SetGlslRayGenShader(const char* glsl, void* pNext = nullptr);
void AddSpirvRayGenShader(const char* spirv, const char* entry_point);
void AddSlangRayGenShader(const char* slang, const char* entry_point);
void AddGlslMissShader(const char* glsl);
void AddSpirvMissShader(const char* spirv, const char* entry_point);
void AddSlangMissShader(const char* slang, const char* entry_point);
void AddGlslClosestHitShader(const char* glsl);
void AddSpirvClosestHitShader(const char* spirv, const char* entry_point);
void AddSlangClosestHitShader(const char* slang, const char* entry_point);
void AddLibrary(const Pipeline& library);
void AddDynamicState(VkDynamicState dynamic_state);
// Build
// -----
void Build();
void BuildPipeline();
void BuildSbt();
void DeferBuild();
// Get
// ---
VkShaderObj& GetRayGenShader(uint32_t ray_gen_i);
const auto& Handle() { return rt_pipeline_; }
operator VkPipeline() const { return rt_pipeline_; }
vkt::PipelineLayout& GetPipelineLayout() { return pipeline_layout_; }
OneOffDescriptorSet& GetDescriptorSet() {
assert(desc_set_);
return *desc_set_;
}
OneOffDescriptorIndexingSet& GetDescriptorIndexingSet() {
assert(desc_indexing_set_);
return *desc_indexing_set_;
}
TraceRaysSbt GetTraceRaysSbt(uint32_t ray_gen_shader_i = 0);
const vkt::Buffer& GetTraceRaysSbtBuffer();
vkt::Buffer GetTraceRaysSbtIndirectBuffer(uint32_t ray_gen_shader_i, uint32_t width, uint32_t height, uint32_t depth);
uint32_t GetShaderGroupsCount();
std::vector<uint8_t> GetRayTracingShaderGroupHandles();
std::vector<uint8_t> GetRayTracingCaptureReplayShaderGroupHandles();
std::vector<VkRayTracingShaderGroupCreateInfoKHR> GetRayTracingShaderGroupCreateInfos();
private:
uint32_t GetRayGenShadersCount() const;
uint32_t GetMissShadersCount() const;
uint32_t GetClosestHitShadersCount() const;
private:
VkLayerTest& test_;
vkt::Device* device_;
VkPipelineCreateFlags2CreateInfo create_flags_2_ = {};
VkRayTracingPipelineCreateInfoKHR vk_info_{};
uint32_t push_constant_range_size_ = 0;
std::vector<VkDescriptorSetLayoutBinding> bindings_{};
std::unique_ptr<OneOffDescriptorSet> desc_set_{};
std::vector<OneOffDescriptorIndexingSet::Binding> desc_indexing_bindings_{};
std::unique_ptr<OneOffDescriptorIndexingSet> desc_indexing_set_{};
VkPipelineLayoutCreateInfo pipeline_layout_ci_;
vkt::PipelineLayout pipeline_layout_{};
std::vector<VkDynamicState> dynamic_states{};
std::vector<std::unique_ptr<VkShaderObj>> ray_gen_shaders_{};
std::vector<std::unique_ptr<VkShaderObj>> miss_shaders_{};
std::vector<std::unique_ptr<VkShaderObj>> closest_hit_shaders_{};
std::vector<VkRayTracingShaderGroupCreateInfoKHR> shader_group_cis_{};
vkt::Pipeline rt_pipeline_{};
VkDeferredOperationKHR deferred_op_ = VK_NULL_HANDLE;
vkt::Buffer sbt_buffer_{};
VkRayTracingPipelineInterfaceCreateInfoKHR rt_pipeline_interface_info_{};
VkPipelineLibraryCreateInfoKHR pipeline_lib_info_{};
std::vector<const Pipeline*> libraries_{};
std::vector<VkPipeline> library_handles_{};
};
} // namespace rt
} // namespace vkt