1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
|
/*
* 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, _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;
};
~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);
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);
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_;
};
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, bool use_ppGeometries = true);
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 GeometrySimpleHostInstance(VkAccelerationStructureKHR host_instance);
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);
} // 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 InitLibraryInfo();
void AddBinding(VkDescriptorType descriptor_type, uint32_t binding, uint32_t descriptor_count = 1);
void CreateDescriptorSet();
// *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 AddSpirvRayGenShader(const char* spirv, const char* entry_point);
void AddGlslMissShader(const char* glsl);
void AddSpirvMissShader(const char* spirv, const char* entry_point);
void AddGlslClosestHitShader(const char* glsl);
void AddSpirvClosestHitShader(const char* spirv, 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_;
}
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:
VkLayerTest& test_;
vkt::Device* device_;
VkRayTracingPipelineCreateInfoKHR vk_info_{};
uint32_t push_constant_range_size_ = 0;
std::vector<VkDescriptorSetLayoutBinding> bindings_{};
std::unique_ptr<OneOffDescriptorSet> desc_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<VkPipeline> libraries_{};
};
} // namespace rt
} // namespace vkt
|