yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
8.9 KiB264 linesraw
1// d3d11-shader-object-layout.h
2#pragma once
3
4#include "d3d11-base.h"
5#include "d3d11-helper-functions.h"
6
7namespace gfx
8{
9
10using namespace Slang;
11
12namespace d3d11
13{
14
15class ShaderObjectLayoutImpl : public ShaderObjectLayoutBase
16{
17public:
18    // A shader object comprises three main kinds of state:
19    //
20    // * Zero or more bytes of ordinary ("uniform") data
21    // * Zero or more *bindings* for textures, buffers, and samplers
22    // * Zero or more *sub-objects* representing nested parameter blocks, etc.
23    //
24    // A shader object *layout* stores information that can be used to
25    // organize these different kinds of state and optimize access to them.
26    //
27    // For example, both texture/buffer/sampler bindings and sub-objects
28    // are organized into logical *binding ranges* by the Slang reflection
29    // API, and a shader object layout will store information about those
30    // ranges in a form that is usable for the D3D11 API:
31
32    /// Information about a logical binding range as reported by Slang reflection
33    struct BindingRangeInfo
34    {
35        /// The type of bindings in this range
36        slang::BindingType bindingType;
37
38        /// The number of bindings in this range
39        Index count;
40
41        /// The starting index for this range in the appropriate "flat" array in a shader object.
42        /// E.g., for a shader resource view range, this would be an index into the `m_srvs` array.
43        Index baseIndex;
44
45        /// The offset of this binding range from the start of the sub-object
46        /// in terms of whatever D3D11 register class it consumes. E.g., for
47        /// a `Texture2D` binding range this will represent an offset in
48        /// `t` registers.
49        ///
50        uint32_t registerOffset;
51
52        /// An index into the sub-object array if this binding range is treated
53        /// as a sub-object.
54        Index subObjectIndex;
55
56        /// Is this binding range specializable, e.g. an existential value or ParameterBlock<IFoo>.
57        bool isSpecializable;
58    };
59
60    // Sometimes we just want to iterate over the ranges that represent
61    // sub-objects while skipping over the others, because sub-object
62    // ranges often require extra handling or more state.
63    //
64    // For that reason we also store pre-computed information about each
65    // sub-object range.
66
67    /// Offset information for a sub-object range
68    struct SubObjectRangeOffset : BindingOffset
69    {
70        SubObjectRangeOffset() {}
71
72        SubObjectRangeOffset(slang::VariableLayoutReflection* varLayout);
73
74        /// The offset for "pending" ordinary data related to this range
75        uint32_t pendingOrdinaryData = 0;
76    };
77
78    /// Stride information for a sub-object range
79    struct SubObjectRangeStride : BindingOffset
80    {
81        SubObjectRangeStride() {}
82
83        SubObjectRangeStride(slang::TypeLayoutReflection* typeLayout);
84
85        /// The strid for "pending" ordinary data related to this range
86        uint32_t pendingOrdinaryData = 0;
87    };
88
89    /// Information about a logical binding range as reported by Slang reflection
90    struct SubObjectRangeInfo
91    {
92        /// The index of the binding range that corresponds to this sub-object range
93        Index bindingRangeIndex;
94
95        /// The layout expected for objects bound to this range (if known)
96        RefPtr<ShaderObjectLayoutImpl> layout;
97
98        /// The offset to use when binding the first object in this range
99        SubObjectRangeOffset offset;
100
101        /// Stride between consecutive objects in this range
102        SubObjectRangeStride stride;
103    };
104
105    struct Builder
106    {
107    public:
108        Builder(RendererBase* renderer, slang::ISession* session)
109            : m_renderer(renderer), m_session(session)
110        {
111        }
112
113        RendererBase* m_renderer;
114        slang::ISession* m_session;
115        slang::TypeLayoutReflection* m_elementTypeLayout;
116
117        List<BindingRangeInfo> m_bindingRanges;
118        List<SubObjectRangeInfo> m_subObjectRanges;
119
120        /// The indices of the binding ranges that represent SRVs
121        List<Index> m_srvRanges;
122
123        /// The indices of the binding ranges that represent UAVs
124        List<Index> m_uavRanges;
125
126        /// The indices of the binding ranges that represent samplers
127        List<Index> m_samplerRanges;
128
129        Index m_srvCount = 0;
130        Index m_samplerCount = 0;
131        Index m_uavCount = 0;
132        Index m_subObjectCount = 0;
133
134        uint32_t m_totalOrdinaryDataSize = 0;
135
136        /// The container type of this shader object. When `m_containerType` is
137        /// `StructuredBuffer` or `UnsizedArray`, this shader object represents a collection
138        /// instead of a single object.
139        ShaderObjectContainerType m_containerType = ShaderObjectContainerType::None;
140
141        Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout);
142        SlangResult build(ShaderObjectLayoutImpl** outLayout);
143    };
144
145    static Result createForElementType(
146        RendererBase* renderer,
147        slang::ISession* session,
148        slang::TypeLayoutReflection* elementType,
149        ShaderObjectLayoutImpl** outLayout);
150
151    List<BindingRangeInfo> const& getBindingRanges() { return m_bindingRanges; }
152
153    Index getBindingRangeCount() { return m_bindingRanges.getCount(); }
154
155    BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; }
156
157    Index getSRVCount() { return m_srvCount; }
158    Index getSamplerCount() { return m_samplerCount; }
159    Index getUAVCount() { return m_uavCount; }
160    Index getSubObjectCount() { return m_subObjectCount; }
161    Index getVaryingOutputCount() { return m_varyingOutputCount; }
162
163    SubObjectRangeInfo const& getSubObjectRange(Index index) { return m_subObjectRanges[index]; }
164    List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; }
165
166    RendererBase* getRenderer() { return m_renderer; }
167
168    slang::TypeReflection* getType() { return m_elementTypeLayout->getType(); }
169
170    /// Get the indices that represent all the SRV ranges in this type
171    List<Index> const& getSRVRanges() const { return m_srvRanges; }
172
173    /// Get the indices that reprsent all the UAV ranges in this type
174    List<Index> const& getUAVRanges() const { return m_uavRanges; }
175
176    /// Get the indices that represnet all the sampler ranges in this type
177    List<Index> const& getSamplerRanges() const { return m_samplerRanges; }
178
179    uint32_t getTotalOrdinaryDataSize() const { return m_totalOrdinaryDataSize; }
180
181protected:
182    Result _init(Builder const* builder);
183
184    List<BindingRangeInfo> m_bindingRanges;
185    List<Index> m_srvRanges;
186    List<Index> m_uavRanges;
187    List<Index> m_samplerRanges;
188    Index m_srvCount = 0;
189    Index m_samplerCount = 0;
190    Index m_uavCount = 0;
191    Index m_subObjectCount = 0;
192    Index m_varyingInputCount = 0;
193    Index m_varyingOutputCount = 0;
194    uint32_t m_totalOrdinaryDataSize = 0;
195    List<SubObjectRangeInfo> m_subObjectRanges;
196};
197
198class RootShaderObjectLayoutImpl : public ShaderObjectLayoutImpl
199{
200    typedef ShaderObjectLayoutImpl Super;
201
202public:
203    struct EntryPointInfo
204    {
205        RefPtr<ShaderObjectLayoutImpl> layout;
206
207        /// The offset for this entry point's parameters, relative to the starting offset for the
208        /// program
209        BindingOffset offset;
210    };
211
212    struct Builder : Super::Builder
213    {
214        Builder(
215            RendererBase* renderer,
216            slang::IComponentType* program,
217            slang::ProgramLayout* programLayout)
218            : Super::Builder(renderer, program->getSession())
219            , m_program(program)
220            , m_programLayout(programLayout)
221        {
222        }
223
224        Result build(RootShaderObjectLayoutImpl** outLayout);
225        void addGlobalParams(slang::VariableLayoutReflection* globalsLayout);
226        void addEntryPoint(
227            SlangStage stage,
228            ShaderObjectLayoutImpl* entryPointLayout,
229            slang::EntryPointLayout* slangEntryPoint);
230
231        slang::IComponentType* m_program;
232        slang::ProgramLayout* m_programLayout;
233        List<EntryPointInfo> m_entryPoints;
234        SimpleBindingOffset m_pendingDataOffset;
235    };
236
237    EntryPointInfo& getEntryPoint(Index index) { return m_entryPoints[index]; }
238
239    List<EntryPointInfo>& getEntryPoints() { return m_entryPoints; }
240
241    static Result create(
242        RendererBase* renderer,
243        slang::IComponentType* program,
244        slang::ProgramLayout* programLayout,
245        RootShaderObjectLayoutImpl** outLayout);
246
247    slang::IComponentType* getSlangProgram() const { return m_program; }
248    slang::ProgramLayout* getSlangProgramLayout() const { return m_programLayout; }
249
250    /// Get the offset at which "pending" shader parameters for this program start
251    SimpleBindingOffset const& getPendingDataOffset() const { return m_pendingDataOffset; }
252
253protected:
254    Result _init(Builder const* builder);
255
256    ComPtr<slang::IComponentType> m_program;
257    slang::ProgramLayout* m_programLayout = nullptr;
258
259    List<EntryPointInfo> m_entryPoints;
260    SimpleBindingOffset m_pendingDataOffset;
261};
262
263} // namespace d3d11
264} // namespace gfx