Skip to content

Commit c586e4b

Browse files
Merge pull request #770 from Devsh-Graphics-Programming/bindless_blit
Pseudo-Concepts for HLSL
2 parents 45db070 + 0c0b9ab commit c586e4b

24 files changed

+776
-522
lines changed

3rdparty/dxc/dxc

Submodule dxc updated 222 files

examples_tests

include/nbl/asset/ICPUComputePipeline.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ICPUComputePipeline : public ICPUPipeline<IPipeline<ICPUPipelineLayout>,1>
2525
{
2626
if (!params.layout)
2727
return nullptr;
28-
auto retval = new ICPUComputePipeline(core::smart_refctd_ptr<ICPUPipelineLayout>(params.layout));
28+
auto retval = new ICPUComputePipeline(core::smart_refctd_ptr<const ICPUPipelineLayout>(params.layout));
2929
if (!retval->setSpecInfo(params.shader))
3030
{
3131
retval->drop();
@@ -48,7 +48,7 @@ class ICPUComputePipeline : public ICPUPipeline<IPipeline<ICPUPipelineLayout>,1>
4848
using base_t::base_t;
4949
virtual ~ICPUComputePipeline() = default;
5050

51-
base_t* clone_impl(core::smart_refctd_ptr<ICPUPipelineLayout>&& layout) const override
51+
base_t* clone_impl(core::smart_refctd_ptr<const ICPUPipelineLayout>&& layout) const override
5252
{
5353
return new ICPUComputePipeline(std::move(layout));
5454
}
@@ -57,7 +57,7 @@ class ICPUComputePipeline : public ICPUPipeline<IPipeline<ICPUPipelineLayout>,1>
5757
{
5858
if (ix!=0)
5959
return m_stages[0].shader.get();
60-
return m_layout.get();
60+
return const_cast<ICPUPipelineLayout*>(m_layout.get());
6161
}
6262

6363
inline int8_t stageToIndex(const ICPUShader::E_SHADER_STAGE stage) const override

include/nbl/asset/ICPUGraphicsPipeline.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class ICPUGraphicsPipeline final : public ICPUPipeline<IGraphicsPipeline<ICPUPip
6565
using base_t::base_t;
6666
~ICPUGraphicsPipeline() = default;
6767

68-
base_t* clone_impl(core::smart_refctd_ptr<ICPUPipelineLayout>&& layout) const override
68+
base_t* clone_impl(core::smart_refctd_ptr<const ICPUPipelineLayout>&& layout) const override
6969
{
7070
std::array<ICPUShader::SSpecInfo,GRAPHICS_SHADER_STAGE_COUNT> _shaders;
7171
for (auto i=0; i<GRAPHICS_SHADER_STAGE_COUNT; i++)
@@ -80,7 +80,7 @@ class ICPUGraphicsPipeline final : public ICPUPipeline<IGraphicsPipeline<ICPUPip
8080
inline IAsset* getDependant_impl(const size_t ix) override
8181
{
8282
if (ix==0)
83-
return m_layout.get();
83+
return const_cast<ICPUPipelineLayout*>(m_layout.get());
8484
if (ix==1)
8585
return m_renderpass.get();
8686
size_t stageCount = 0;

include/nbl/asset/ICPUPipeline.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase
5151
ICPUPipelineLayout* getLayout()
5252
{
5353
assert(isMutable());
54-
return PipelineNonAssetBase::m_layout.get();
54+
return const_cast<ICPUPipelineLayout*>(PipelineNonAssetBase::m_layout.get());
5555
}
5656
const ICPUPipelineLayout* getLayout() const { return PipelineNonAssetBase::m_layout.get(); }
5757

58-
inline void setLayout(core::smart_refctd_ptr<ICPUPipelineLayout>&& _layout)
58+
inline void setLayout(core::smart_refctd_ptr<const ICPUPipelineLayout>&& _layout)
5959
{
6060
assert(isMutable());
6161
PipelineNonAssetBase::m_layout = std::move(_layout);
@@ -117,7 +117,7 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase
117117
using PipelineNonAssetBase::PipelineNonAssetBase;
118118
virtual ~ICPUPipeline() = default;
119119

120-
virtual this_t* clone_impl(core::smart_refctd_ptr<ICPUPipelineLayout>&& layout) const = 0;
120+
virtual this_t* clone_impl(core::smart_refctd_ptr<const ICPUPipelineLayout>&& layout) const = 0;
121121
virtual int8_t stageToIndex(const ICPUShader::E_SHADER_STAGE stage) const = 0;
122122

123123
struct ShaderStage {

include/nbl/asset/IGraphicsPipeline.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class IGraphicsPipeline : public IPipeline<PipelineLayoutType>, public IGraphics
155155

156156
protected:
157157
explicit IGraphicsPipeline(const SCreationParams& _params) :
158-
IPipeline<PipelineLayoutType>(core::smart_refctd_ptr<PipelineLayoutType>(_params.layout)),
158+
IPipeline<PipelineLayoutType>(core::smart_refctd_ptr<const PipelineLayoutType>(_params.layout)),
159159
m_params(_params.cached), m_renderpass(core::smart_refctd_ptr<renderpass_t>(_params.renderpass)) {}
160160

161161
SCachedCreationParams m_params;

include/nbl/asset/IPipeline.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class IPipeline
3535
struct SCreationParams
3636
{
3737
public:
38-
PipelineLayout* layout = nullptr;
38+
const PipelineLayout* layout = nullptr;
3939

4040
protected:
4141
// This is not public to make sure that different pipelines only get the enums they support
@@ -107,9 +107,9 @@ class IPipeline
107107
inline const PipelineLayout* getLayout() const {return m_layout.get();}
108108

109109
protected:
110-
inline IPipeline(core::smart_refctd_ptr<PipelineLayout>&& _layout) : m_layout(std::move(_layout)) {}
110+
inline IPipeline(core::smart_refctd_ptr<const PipelineLayout>&& _layout) : m_layout(std::move(_layout)) {}
111111

112-
core::smart_refctd_ptr<PipelineLayout> m_layout;
112+
core::smart_refctd_ptr<const PipelineLayout> m_layout;
113113
};
114114

115115
}

include/nbl/asset/IPipelineLayout.h

+53-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
#ifndef _NBL_ASSET_I_PIPELINE_LAYOUT_H_INCLUDED_
55
#define _NBL_ASSET_I_PIPELINE_LAYOUT_H_INCLUDED_
66

7+
#include "nbl/macros.h"
8+
#include "nbl/core/declarations.h"
79

810
#include <algorithm>
911
#include <array>
1012

11-
#include "nbl/macros.h"
12-
#include "nbl/core/declarations.h"
13+
#include "nbl/asset/IDescriptorSetLayout.h"
14+
#include "nbl/builtin/hlsl/binding_info.hlsl"
1315

1416

1517
namespace nbl::asset
@@ -21,7 +23,7 @@ namespace nbl::asset
2123
however they serve as a fast path with regard to data upload from the
2224
CPU and data access from the GPU.
2325
24-
Note that IrrlichtBaW limits push constant size to 128 bytes.
26+
Note that Nabla limits push constant size to 128 bytes.
2527
2628
Push Constants are an alternative to an UBO where it performs really poorly,
2729
mostly very small and very frequent updates. Examples of which are:
@@ -140,6 +142,54 @@ class IPipelineLayout
140142
return static_cast<int32_t>(i)-1;
141143
}
142144

145+
// utility function, if you compile shaders for specific layouts, not create layouts given shaders
146+
struct SBindingKey
147+
{
148+
using type_bitset_t = std::bitset<static_cast<size_t>(IDescriptor::E_TYPE::ET_COUNT)>;
149+
150+
hlsl::SBindingInfo binding = {};
151+
core::bitflag<IShader::E_SHADER_STAGE> requiredStages = IShader::E_SHADER_STAGE::ESS_UNKNOWN;
152+
// could have just initialized with `~type_bitset_t()` in C++23
153+
type_bitset_t allowedTypes = type_bitset_t((0x1u<<static_cast<size_t>(IDescriptor::E_TYPE::ET_COUNT))-1);
154+
};
155+
// TODO: add constraints for stage and creation flags, or just return the storage index & redirect?
156+
core::string getBindingInfoForHLSL(const SBindingKey& key) const
157+
{
158+
if (key.binding.set>=DESCRIPTOR_SET_COUNT)
159+
return "#error \"IPipelineLayout::SBindingKey::binding::set out of range!\"";
160+
const auto* layout = m_descSetLayouts[key.binding.set].get();
161+
if (!layout)
162+
return "#error \"IPipelineLayout::SBindingKey::binding::set layout is nullptr!\"";
163+
//
164+
using redirect_t = IDescriptorSetLayoutBase::CBindingRedirect;
165+
using storage_range_index_t = redirect_t::storage_range_index_t;
166+
const redirect_t* redirect;
167+
storage_range_index_t found;
168+
{
169+
const redirect_t::binding_number_t binding(key.binding.binding);
170+
for (auto t=0u; t<static_cast<size_t>(IDescriptor::E_TYPE::ET_COUNT); t++)
171+
if (key.allowedTypes.test(t))
172+
{
173+
redirect = &layout->getDescriptorRedirect(static_cast<IDescriptor::E_TYPE>(t));
174+
found = redirect->findBindingStorageIndex(binding);
175+
if (found)
176+
break;
177+
}
178+
if (!found && key.allowedTypes.test(static_cast<size_t>(IDescriptor::E_TYPE::ET_SAMPLER)))
179+
{
180+
redirect = &layout->getImmutableSamplerRedirect();
181+
found = redirect->findBindingStorageIndex(binding);
182+
}
183+
if (!found)
184+
return "#error \"Could not find `IPipelineLayout::SBindingKey::binding::binding` in `IPipelineLayout::SBindingKey::binding::set`'s layout!\"";
185+
}
186+
if (!redirect->getStageFlags(found).hasFlags(key.requiredStages))
187+
return "#error \"Binding found in the layout doesn't have all the `IPipelineLayout::SBindingKey::binding::requiredStages` flags!\"";
188+
const auto count = redirect->getCount(found);
189+
assert(count); // this layout should have never passed validation
190+
return "::nbl::hlsl::ConstevalBindingInfo<"+std::to_string(key.binding.set)+","+std::to_string(key.binding.binding)+","+std::to_string(count)+">";
191+
}
192+
143193
protected:
144194
IPipelineLayout(
145195
const std::span<const asset::SPushConstantRange> _pcRanges,
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (C) 2024 - 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+
#ifndef _NBL_BUILTIN_HLSL_BINDING_INFO_INCLUDED_
5+
#define _NBL_BUILTIN_HLSL_BINDING_INFO_INCLUDED_
6+
7+
#include "nbl/builtin/hlsl/cpp_compat.hlsl"
8+
9+
namespace nbl
10+
{
11+
namespace hlsl
12+
{
13+
14+
template<uint32_t set, uint32_t ix, uint32_t count=1>
15+
struct ConstevalBindingInfo
16+
{
17+
NBL_CONSTEXPR_STATIC_INLINE uint32_t Set = set;
18+
NBL_CONSTEXPR_STATIC_INLINE uint32_t Index = ix;
19+
NBL_CONSTEXPR_STATIC_INLINE uint32_t Count = count;
20+
};
21+
22+
// used for descriptor set layout lookups
23+
struct SBindingInfo
24+
{
25+
//! binding index for a given resource
26+
uint32_t binding : 29;
27+
//! descriptor set index for a resource
28+
uint32_t set : 3;
29+
};
30+
31+
}
32+
}
33+
#endif

include/nbl/builtin/hlsl/blit/common.hlsl

+50-57
Original file line numberDiff line numberDiff line change
@@ -4,84 +4,77 @@
44
#ifndef _NBL_BUILTIN_HLSL_BLIT_COMMON_INCLUDED_
55
#define _NBL_BUILTIN_HLSL_BLIT_COMMON_INCLUDED_
66

7-
#include <nbl/builtin/hlsl/cpp_compat.hlsl>
7+
#include <nbl/builtin/hlsl/binding_info.hlsl>
88

99
namespace nbl
1010
{
1111
namespace hlsl
1212
{
13-
namespace blit
13+
namespace glsl
1414
{
15-
namespace impl
15+
uint32_t3 gl_WorkGroupSize()
1616
{
17+
return uint32_t3(ConstevalParameters::WorkGroupSize,1,1);
18+
}
19+
}
20+
}
21+
}
1722

18-
template <uint32_t Dimension>
19-
struct dim_to_image_properties { };
23+
using namespace nbl::hlsl;
24+
25+
[[vk::binding(ConstevalParameters::kernel_weight_binding_t::Index,ConstevalParameters::kernel_weight_binding_t::Set)]]
26+
Buffer<float32_t4> kernelWeights[ConstevalParameters::kernel_weight_binding_t::Count];
27+
[[vk::binding(ConstevalParameters::input_sampler_binding_t::Index,ConstevalParameters::input_sampler_binding_t::Set)]]
28+
SamplerState inSamp[ConstevalParameters::input_sampler_binding_t::Count];
29+
// aliased
30+
[[vk::binding(ConstevalParameters::input_image_binding_t::Index,ConstevalParameters::input_image_binding_t::Set)]]
31+
Texture1DArray<float4> inAs1DArray[ConstevalParameters::input_image_binding_t::Count];
32+
[[vk::binding(ConstevalParameters::input_image_binding_t::Index,ConstevalParameters::input_image_binding_t::Set)]]
33+
Texture2DArray<float4> inAs2DArray[ConstevalParameters::input_image_binding_t::Count];
34+
[[vk::binding(ConstevalParameters::input_image_binding_t::Index,ConstevalParameters::input_image_binding_t::Set)]]
35+
Texture3D<float4> inAs3D[ConstevalParameters::input_image_binding_t::Count];
36+
// aliased
37+
[[vk::binding(ConstevalParameters::output_binding_t::Index,ConstevalParameters::output_binding_t::Set)]] [[vk::image_format("unknown")]]
38+
RWTexture1DArray<float4> outAs1DArray[ConstevalParameters::output_binding_t::Count];
39+
[[vk::binding(ConstevalParameters::output_binding_t::Index,ConstevalParameters::output_binding_t::Set)]] [[vk::image_format("unknown")]]
40+
RWTexture2DArray<float4> outAs2DArray[ConstevalParameters::output_binding_t::Count];
41+
[[vk::binding(ConstevalParameters::output_binding_t::Index,ConstevalParameters::output_binding_t::Set)]] [[vk::image_format("unknown")]]
42+
RWTexture3D<float4> outAs3D[ConstevalParameters::output_binding_t::Count];
2043

21-
template <>
22-
struct dim_to_image_properties<1>
23-
{
24-
using combined_sampler_t = Texture1DArray<float4>;
25-
using image_t = RWTexture1DArray<float4>;
2644

27-
template <typename T>
28-
static vector<T, 2> getIndexCoord(vector<T, 3> coords, uint32_t layer)
45+
groupshared uint32_t sMem[ConstevalParameters::SharedMemoryDWORDs];
46+
/*
47+
struct HistogramAccessor
48+
{
49+
void atomicAdd(uint32_t wgID, uint32_t bucket, uint32_t v)
2950
{
30-
return vector<T, 2>(coords.x, layer);
51+
InterlockedAdd(statsBuff[wgID * (ConstevalParameters::AlphaBinCount + 1) + bucket], v);
3152
}
3253
};
33-
34-
template <>
35-
struct dim_to_image_properties<2>
54+
struct SharedAccessor
3655
{
37-
using combined_sampler_t = Texture2DArray<float4>;
38-
using image_t = RWTexture2DArray<float4>;
39-
40-
template <typename T>
41-
static vector<T,3> getIndexCoord(vector<T, 3> coords, uint32_t layer)
56+
float32_t get(float32_t idx)
4257
{
43-
return vector<T, 3>(coords.xy, layer);
58+
return sMem[idx];
59+
}
60+
void set(float32_t idx, float32_t val)
61+
{
62+
sMem[idx] = val;
4463
}
4564
};
46-
47-
template <>
48-
struct dim_to_image_properties<3>
65+
struct InCSAccessor
4966
{
50-
using combined_sampler_t = Texture3D<float4>;
51-
using image_t = RWTexture3D<float4>;
52-
53-
template <typename T>
54-
static vector<T, 3> getIndexCoord(vector<T, 3> coords, uint32_t layer)
67+
float32_t4 get(float32_t3 c, uint32_t l)
5568
{
56-
return vector<T,3>(coords);
69+
return inCS.SampleLevel(inSamp, blit::impl::dim_to_image_properties<ConstevalParameters::BlitDimCount>::getIndexCoord<float32_t>(c, l), 0);
5770
}
5871
};
59-
60-
}
61-
62-
63-
template<
64-
uint32_t _WorkGroupSizeX,
65-
uint32_t _WorkGroupSizeY,
66-
uint32_t _WorkGroupSizeZ,
67-
uint32_t _SMemFloatsPerChannel,
68-
uint32_t _BlitOutChannelCount,
69-
uint32_t _BlitDimCount,
70-
uint32_t _AlphaBinCount>
71-
struct consteval_parameters_t
72+
struct OutImgAccessor
7273
{
73-
NBL_CONSTEXPR_STATIC_INLINE uint32_t SMemFloatsPerChannel = _SMemFloatsPerChannel;
74-
NBL_CONSTEXPR_STATIC_INLINE uint32_t BlitOutChannelCount = _BlitOutChannelCount;
75-
NBL_CONSTEXPR_STATIC_INLINE uint32_t BlitDimCount = _BlitDimCount;
76-
NBL_CONSTEXPR_STATIC_INLINE uint32_t AlphaBinCount = _AlphaBinCount;
77-
NBL_CONSTEXPR_STATIC_INLINE uint32_t WorkGroupSizeX = _WorkGroupSizeX;
78-
NBL_CONSTEXPR_STATIC_INLINE uint32_t WorkGroupSizeY = _WorkGroupSizeY;
79-
NBL_CONSTEXPR_STATIC_INLINE uint32_t WorkGroupSizeZ = _WorkGroupSizeZ;
80-
NBL_CONSTEXPR_STATIC_INLINE uint32_t WorkGroupSize = WorkGroupSizeX * WorkGroupSizeY * WorkGroupSizeZ;
74+
void set(int32_t3 c, uint32_t l, float32_t4 v)
75+
{
76+
outImg[blit::impl::dim_to_image_properties<ConstevalParameters::BlitDimCount>::getIndexCoord<int32_t>(c, l)] = v;
77+
}
8178
};
82-
83-
}
84-
}
85-
}
86-
79+
*/
8780
#endif

0 commit comments

Comments
 (0)