Skip to content

Commit 679304c

Browse files
Merge pull request #820 from kevyuu/raytracing_pipeline
Ray Tracing Pipeline
2 parents 28ba56f + 3fd2e14 commit 679304c

31 files changed

+1385
-33
lines changed

include/nbl/asset/ECommonEnums.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ enum E_PIPELINE_BIND_POINT : uint8_t
1111
{
1212
EPBP_GRAPHICS = 0,
1313
EPBP_COMPUTE,
14-
14+
EPBP_RAY_TRACING,
1515
EPBP_COUNT
1616
};
1717

include/nbl/asset/IPipeline.h

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,45 +54,57 @@ class IPipeline
5454
// Compute Pipelines only
5555
//DISPATCH_BASE = 1<<4,
5656

57-
// Weird extension
57+
// This is for NV-raytracing extension. Now this is done via IDeferredOperation
5858
//DEFER_COMPILE_NV = 1<<5,
5959

60-
CAPTURE_STATISTICS = 1<<6,
61-
CAPTURE_INTERNAL_REPRESENTATIONS = 1<<7,
60+
// We use Renderdoc to take care of this for us,
61+
// we won't be parsing the statistics and internal representation ourselves.
62+
//CAPTURE_STATISTICS = 1<<6,
63+
//CAPTURE_INTERNAL_REPRESENTATIONS = 1<<7,
6264

63-
// We require Pipeline Cache Control feature so those are satisfied:
64-
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkComputePipelineCreateInfo.html#VUID-VkComputePipelineCreateInfo-pipelineCreationCacheControl-02875
65+
// Will soon be deprecated due to
66+
// https://github.com/Devsh-Graphics-Programming/Nabla/issues/854
6567
FAIL_ON_PIPELINE_COMPILE_REQUIRED = 1<<8,
6668
EARLY_RETURN_ON_FAILURE = 1<<9,
6769

68-
LINK_TIME_OPTIMIZATION = 1<<10,
70+
// Will be exposed later with the IPipelineLibrary asset implementation
71+
// https://github.com/Devsh-Graphics-Programming/Nabla/issues/853
72+
//LINK_TIME_OPTIMIZATION = 1<<10,
6973

70-
//Not Supported Yet
74+
// Won't be exposed because we'll introduce Libraries as a separate object/asset-type
75+
// https://github.com/Devsh-Graphics-Programming/Nabla/issues/853
7176
//CREATE_LIBRARY = 1<<11,
7277

7378
// Ray Tracing Pipelines only
74-
//RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 1<<12,
75-
//RAY_TRACING_SKIP_AABBS_BIT_KHR = 1<<13,
76-
//RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 1<<14,
77-
//RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 1<<15,
78-
//RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 1<<16,
79-
//RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 1<<17,
80-
81-
// Not Supported Yet
79+
//SKIP_BUILT_IN_PRIMITIVES = 1<<12,
80+
//SKIP_AABBS = 1<<13,
81+
//NO_NULL_ANY_HIT_SHADERS = 1<<14,
82+
//NO_NULL_CLOSEST_HIT_SHADERS = 1<<15,
83+
//NO_NULL_MISS_SHADERS = 1<<16,
84+
//NO_NULL_INTERSECTION_SHADERS = 1<<17,
85+
86+
// There is a new Device Generated Commands extension with its own flag that will deprecate this
8287
//INDIRECT_BINDABLE_NV = 1<<18,
8388

8489
// Ray Tracing Pipelines only
90+
// For debug tools
8591
//RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 1<<19,
86-
//RAY_TRACING_ALLOW_MOTION_BIT_NV = 1<<20,
92+
93+
// Ray Tracing Pipelines only
94+
//ALLOW_MOTION = 1<<20,
8795

8896
// Graphics Pipelineonly (we don't support subpass shading)
8997
//RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1<<21,
9098
//RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 1<<22,
9199

92-
RETAIN_LINK_TIME_OPTIMIZATION_INFO = 1<<23,
100+
// Will be exposed later with the IPipelineLibrary asset implementation
101+
// https://github.com/Devsh-Graphics-Programming/Nabla/issues/853
102+
//RETAIN_LINK_TIME_OPTIMIZATION_INFO = 1<<23,
93103

94104
// Ray Tracing Pipelines only
95105
//RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 1<<24,
106+
107+
// Not supported yet, and we will move to dynamic rendering, so this might never be supported
96108
//COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 1<<25,
97109
//DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 1<<26,
98110

@@ -107,7 +119,8 @@ class IPipeline
107119
inline const PipelineLayout* getLayout() const {return m_layout.get();}
108120

109121
protected:
110-
inline IPipeline(core::smart_refctd_ptr<const PipelineLayout>&& _layout) : m_layout(std::move(_layout)) {}
122+
inline IPipeline(core::smart_refctd_ptr<const PipelineLayout>&& _layout)
123+
: m_layout(std::move(_layout)) {}
111124

112125
core::smart_refctd_ptr<const PipelineLayout> m_layout;
113126
};
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#ifndef _NBL_ASSET_I_RAY_TRACING_PIPELINE_H_INCLUDED_
2+
#define _NBL_ASSET_I_RAY_TRACING_PIPELINE_H_INCLUDED_
3+
4+
#include "nbl/asset/IShader.h"
5+
#include "nbl/asset/IPipeline.h"
6+
7+
#include <span>
8+
#include <bit>
9+
#include <type_traits>
10+
11+
namespace nbl::asset
12+
{
13+
14+
class IRayTracingPipelineBase : public virtual core::IReferenceCounted
15+
{
16+
public:
17+
struct SShaderGroupsParams
18+
{
19+
struct SIndex
20+
{
21+
constexpr static inline uint32_t Unused = 0xffFFffFFu;
22+
uint32_t index = Unused;
23+
};
24+
25+
struct SHitGroup
26+
{
27+
uint32_t closestHit = SIndex::Unused;
28+
uint32_t anyHit = SIndex::Unused;
29+
uint32_t intersection = SIndex::Unused;
30+
};
31+
32+
SIndex raygen;
33+
std::span<SIndex> misses;
34+
std::span<SHitGroup> hits;
35+
std::span<SIndex> callables;
36+
37+
inline uint32_t getShaderGroupCount() const
38+
{
39+
return 1 + hits.size() + misses.size() + callables.size();
40+
}
41+
42+
};
43+
using SGeneralShaderGroup = SShaderGroupsParams::SIndex;
44+
using SHitShaderGroup = SShaderGroupsParams::SHitGroup;
45+
46+
struct SCachedCreationParams final
47+
{
48+
uint32_t maxRecursionDepth : 6 = 0;
49+
uint32_t dynamicStackSize : 1 = false;
50+
};
51+
};
52+
53+
template<typename PipelineLayoutType, typename ShaderType>
54+
class IRayTracingPipeline : public IPipeline<PipelineLayoutType>, public IRayTracingPipelineBase
55+
{
56+
using base_creation_params_t = IPipeline<PipelineLayoutType>::SCreationParams;
57+
public:
58+
59+
using SGeneralShaderGroupContainer = core::smart_refctd_dynamic_array<SGeneralShaderGroup>;
60+
using SHitShaderGroupContainer = core::smart_refctd_dynamic_array<SHitShaderGroup>;
61+
62+
struct SCreationParams : base_creation_params_t
63+
{
64+
public:
65+
#define base_flag(F) static_cast<uint64_t>(base_creation_params_t::FLAGS::F)
66+
enum class FLAGS : uint64_t
67+
{
68+
NONE = base_flag(NONE),
69+
DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS),
70+
ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES),
71+
FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED),
72+
EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE),
73+
SKIP_BUILT_IN_PRIMITIVES = 1<<12,
74+
SKIP_AABBS = 1<<13,
75+
NO_NULL_ANY_HIT_SHADERS = 1<<14,
76+
NO_NULL_CLOSEST_HIT_SHADERS = 1<<15,
77+
NO_NULL_MISS_SHADERS = 1<<16,
78+
NO_NULL_INTERSECTION_SHADERS = 1<<17,
79+
ALLOW_MOTION = 1<<20,
80+
};
81+
#undef base_flag
82+
83+
protected:
84+
using SpecInfo = ShaderType::SSpecInfo;
85+
template<typename ExtraLambda>
86+
inline bool impl_valid(ExtraLambda&& extra) const
87+
{
88+
if (!IPipeline<PipelineLayoutType>::SCreationParams::layout)
89+
return false;
90+
91+
for (const auto info : shaders)
92+
{
93+
if (info.shader)
94+
{
95+
if (!extra(info))
96+
return false;
97+
const auto stage = info.shader->getStage();
98+
if ((stage & ~ICPUShader::E_SHADER_STAGE::ESS_ALL_RAY_TRACING) != 0)
99+
return false;
100+
if (!std::has_single_bit<std::underlying_type_t<ICPUShader::E_SHADER_STAGE>>(stage))
101+
return false;
102+
}
103+
else
104+
{
105+
// every shader must not be null. use SIndex::Unused to represent unused shader.
106+
return false;
107+
}
108+
}
109+
110+
auto getShaderStage = [this](size_t index) -> ICPUShader::E_SHADER_STAGE
111+
{
112+
return shaders[index].shader->getStage();
113+
};
114+
115+
auto isValidShaderIndex = [this, getShaderStage](size_t index, ICPUShader::E_SHADER_STAGE expectedStage, bool is_unused_shader_forbidden) -> bool
116+
{
117+
if (index == SShaderGroupsParams::SIndex::Unused)
118+
return !is_unused_shader_forbidden;
119+
if (index >= shaders.size())
120+
return false;
121+
if (getShaderStage(index) != expectedStage)
122+
return false;
123+
return true;
124+
};
125+
126+
if (!isValidShaderIndex(shaderGroups.raygen.index, ICPUShader::E_SHADER_STAGE::ESS_RAYGEN, true))
127+
{
128+
return false;
129+
}
130+
131+
for (const auto& shaderGroup : shaderGroups.hits)
132+
{
133+
// https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03470
134+
if (!isValidShaderIndex(shaderGroup.anyHit,
135+
ICPUShader::E_SHADER_STAGE::ESS_ANY_HIT,
136+
bool(flags & FLAGS::NO_NULL_ANY_HIT_SHADERS)))
137+
return false;
138+
139+
// https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03471
140+
if (!isValidShaderIndex(shaderGroup.closestHit,
141+
ICPUShader::E_SHADER_STAGE::ESS_CLOSEST_HIT,
142+
bool(flags & FLAGS::NO_NULL_CLOSEST_HIT_SHADERS)))
143+
return false;
144+
145+
if (!isValidShaderIndex(shaderGroup.intersection,
146+
ICPUShader::E_SHADER_STAGE::ESS_INTERSECTION,
147+
false))
148+
return false;
149+
}
150+
151+
for (const auto& shaderGroup : shaderGroups.misses)
152+
{
153+
if (!isValidShaderIndex(shaderGroup.index,
154+
ICPUShader::E_SHADER_STAGE::ESS_MISS,
155+
false))
156+
return false;
157+
}
158+
159+
for (const auto& shaderGroup : shaderGroups.callables)
160+
{
161+
if (!isValidShaderIndex(shaderGroup.index, ICPUShader::E_SHADER_STAGE::ESS_CALLABLE, false))
162+
return false;
163+
}
164+
return true;
165+
}
166+
167+
public:
168+
inline bool valid() const
169+
{
170+
return impl_valid([](const SpecInfo& info)->bool
171+
{
172+
if (!info.valid())
173+
return false;
174+
return false;
175+
});
176+
}
177+
178+
std::span<const SpecInfo> shaders = {};
179+
SShaderGroupsParams shaderGroups;
180+
SCachedCreationParams cached = {};
181+
// TODO: Could guess the required flags from SPIR-V introspection of declared caps
182+
core::bitflag<FLAGS> flags = FLAGS::NONE;
183+
};
184+
185+
inline const SCachedCreationParams& getCachedCreationParams() const { return m_params; }
186+
187+
protected:
188+
explicit IRayTracingPipeline(const SCreationParams& _params) :
189+
IPipeline<PipelineLayoutType>(core::smart_refctd_ptr<const PipelineLayoutType>(_params.layout)),
190+
m_params(_params.cached),
191+
m_raygenShaderGroup(_params.shaderGroups.raygen),
192+
m_missShaderGroups(core::make_refctd_dynamic_array<SGeneralShaderGroupContainer>(_params.shaderGroups.misses)),
193+
m_hitShaderGroups(core::make_refctd_dynamic_array<SHitShaderGroupContainer>(_params.shaderGroups.hits)),
194+
m_callableShaderGroups(core::make_refctd_dynamic_array<SGeneralShaderGroupContainer>(_params.shaderGroups.callables))
195+
{}
196+
197+
SCachedCreationParams m_params;
198+
SGeneralShaderGroup m_raygenShaderGroup;
199+
SGeneralShaderGroupContainer m_missShaderGroups;
200+
SHitShaderGroupContainer m_hitShaderGroups;
201+
SGeneralShaderGroupContainer m_callableShaderGroups;
202+
203+
};
204+
205+
}
206+
207+
#endif

include/nbl/builtin/hlsl/enums.hlsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ enum ShaderStage : uint32_t
2929
ESS_INTERSECTION = 1 << 12,
3030
ESS_CALLABLE = 1 << 13,
3131
ESS_ALL_GRAPHICS = 0x0000001F,
32+
ESS_ALL_RAY_TRACING = ESS_RAYGEN | ESS_ANY_HIT | ESS_CLOSEST_HIT | ESS_MISS | ESS_INTERSECTION | ESS_CALLABLE,
3233
ESS_ALL_OR_LIBRARY = 0x7fffffff
3334
};
3435

include/nbl/builtin/hlsl/indirect_commands.hlsl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ struct DispatchIndirectCommand_t
3737
uint32_t num_groups_z;
3838
};
3939

40+
struct TraceRaysIndirectCommand_t
41+
{
42+
uint64_t raygenShaderRecordAddress;
43+
uint64_t raygenShaderRecordSize;
44+
uint64_t missShaderBindingTableAddress;
45+
uint64_t missShaderBindingTableSize;
46+
uint64_t missShaderBindingTableStride;
47+
uint64_t hitShaderBindingTableAddress;
48+
uint64_t hitShaderBindingTableSize;
49+
uint64_t hitShaderBindingTableStride;
50+
uint64_t callableShaderBindingTableAddress;
51+
uint64_t callableShaderBindingTableSize;
52+
uint64_t callableShaderBindingTableStride;
53+
uint32_t width;
54+
uint32_t height;
55+
uint32_t depth;
56+
};
57+
4058
}
4159
}
4260

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
5+
#ifndef _NBL_BUILTIN_GLSL_RANDOM_LCG_HLSL_INCLUDED_
6+
#define _NBL_BUILTIN_GLSL_RANDOM_LCG_HLSL_INCLUDED_
7+
8+
namespace nbl
9+
{
10+
namespace hlsl
11+
{
12+
13+
struct Lcg
14+
{
15+
static Lcg construct(NBL_CONST_REF_ARG(uint32_t) state)
16+
{
17+
return Lcg(state);
18+
}
19+
20+
uint32_t2 operator()()
21+
{
22+
uint32_t LCG_A = 1664525u;
23+
uint32_t LCG_C = 1013904223u;
24+
state = (LCG_A * state + LCG_C);
25+
state &= 0x00FFFFFF;
26+
return state;
27+
}
28+
29+
uint32_t state;
30+
};
31+
32+
}
33+
}
34+
#endif

0 commit comments

Comments
 (0)