yum-mirror/slang

Making it easier to work with shaders

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

kaizhangNVImplement parameter block to slang-gfx for Metal backend (#6577)ac0dc491e

master
8.7 KiB261 linesraw
1// metal-shader-object-layout.h
2#pragma once
3
4#include "metal-base.h"
5#include "metal-helper-functions.h"
6
7namespace gfx
8{
9
10using namespace Slang;
11
12namespace metal
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 Metal 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 buffers range, this would be an index into the `m_buffers` array.
43        Index baseIndex;
44
45        /// The offset of this binding range from the start of the sub-object.
46        uint32_t registerOffset;
47
48        /// An index into the sub-object array if this binding range is treated
49        /// as a sub-object.
50        Index subObjectIndex;
51
52        /// TODO remove this once specialization is removed
53        bool isSpecializable = false;
54    };
55
56    // Sometimes we just want to iterate over the ranges that represent
57    // sub-objects while skipping over the others, because sub-object
58    // ranges often require extra handling or more state.
59    //
60    // For that reason we also store pre-computed information about each
61    // sub-object range.
62
63    /// Offset information for a sub-object range
64    struct SubObjectRangeOffset : BindingOffset
65    {
66        SubObjectRangeOffset() {}
67
68        SubObjectRangeOffset(slang::VariableLayoutReflection* varLayout);
69
70        /// The offset for "pending" ordinary data related to this range
71        uint32_t pendingOrdinaryData = 0;
72    };
73
74    /// Stride information for a sub-object range
75    struct SubObjectRangeStride : BindingOffset
76    {
77        SubObjectRangeStride() {}
78
79        SubObjectRangeStride(slang::TypeLayoutReflection* typeLayout);
80
81        /// The stride for "pending" ordinary data related to this range
82        uint32_t pendingOrdinaryData = 0;
83    };
84
85    /// Information about a logical binding range as reported by Slang reflection
86    struct SubObjectRangeInfo
87    {
88        /// The index of the binding range that corresponds to this sub-object range
89        Index bindingRangeIndex;
90
91        /// The layout expected for objects bound to this range (if known)
92        RefPtr<ShaderObjectLayoutImpl> layout;
93
94        /// The offset to use when binding the first object in this range
95        SubObjectRangeOffset offset;
96
97        /// Stride between consecutive objects in this range
98        SubObjectRangeStride stride;
99    };
100
101    struct Builder
102    {
103    public:
104        Builder(RendererBase* renderer, slang::ISession* session)
105            : m_renderer(renderer), m_session(session)
106        {
107        }
108
109        RendererBase* m_renderer;
110        slang::ISession* m_session;
111        slang::TypeLayoutReflection* m_elementTypeLayout;
112
113        List<BindingRangeInfo> m_bindingRanges;
114        List<SubObjectRangeInfo> m_subObjectRanges;
115
116        /// The indices of the binding ranges that represent buffers
117        List<Index> m_bufferRanges;
118
119        /// The indices of the binding ranges that represent textures
120        List<Index> m_textureRanges;
121
122        /// The indices of the binding ranges that represent samplers
123        List<Index> m_samplerRanges;
124
125        Index m_bufferCount = 0;
126        Index m_textureCount = 0;
127        Index m_samplerCount = 0;
128        Index m_subObjectCount = 0;
129
130        uint32_t m_totalOrdinaryDataSize = 0;
131
132        /// The container type of this shader object. When `m_containerType` is
133        /// `StructuredBuffer` or `Array`, this shader object represents a collection
134        /// instead of a single object.
135        ShaderObjectContainerType m_containerType = ShaderObjectContainerType::None;
136
137        Result setElementTypeLayout(slang::TypeLayoutReflection* typeLayout);
138        SlangResult build(ShaderObjectLayoutImpl** outLayout);
139    };
140
141    static Result createForElementType(
142        RendererBase* renderer,
143        slang::ISession* session,
144        slang::TypeLayoutReflection* elementType,
145        ShaderObjectLayoutImpl** outLayout);
146
147    List<BindingRangeInfo> const& getBindingRanges() { return m_bindingRanges; }
148
149    Index getBindingRangeCount() { return m_bindingRanges.getCount(); }
150
151    BindingRangeInfo const& getBindingRange(Index index) { return m_bindingRanges[index]; }
152
153    Index getBufferCount() { return m_bufferCount; }
154    Index getTextureCount() { return m_textureCount; }
155    Index getSamplerCount() { return m_samplerCount; }
156    Index getSubObjectCount() { return m_subObjectCount; }
157
158    SubObjectRangeInfo const& getSubObjectRange(Index index) { return m_subObjectRanges[index]; }
159    List<SubObjectRangeInfo> const& getSubObjectRanges() { return m_subObjectRanges; }
160
161    RendererBase* getRenderer() { return m_renderer; }
162
163    slang::TypeReflection* getType() { return m_elementTypeLayout->getType(); }
164
165    /// Get the indices that represent all the buffer ranges in this type
166    List<Index> const& getBufferRanges() const { return m_bufferRanges; }
167
168    /// Get the indices that reprsent all the texture ranges in this type
169    List<Index> const& getTextureRanges() const { return m_textureRanges; }
170
171    /// Get the indices that represnet all the sampler ranges in this type
172    List<Index> const& getSamplerRanges() const { return m_samplerRanges; }
173
174    uint32_t getTotalOrdinaryDataSize() const { return m_totalOrdinaryDataSize; }
175
176    slang::TypeLayoutReflection* getParameterBlockTypeLayout();
177
178    bool isParameterBlock() const { return m_isParameterBlock; }
179    void setIsParameterBlock() { m_isParameterBlock = true; }
180
181protected:
182    Result _init(Builder const* builder);
183
184    List<BindingRangeInfo> m_bindingRanges;
185    List<Index> m_bufferRanges;
186    List<Index> m_textureRanges;
187    List<Index> m_samplerRanges;
188    Index m_bufferCount = 0;
189    Index m_textureCount = 0;
190    Index m_samplerCount = 0;
191    Index m_subObjectCount = 0;
192    uint32_t m_totalOrdinaryDataSize = 0;
193    List<SubObjectRangeInfo> m_subObjectRanges;
194
195    bool m_isParameterBlock = false;
196    // The type layout to use when the shader object is bind as a parameter block.
197    slang::TypeLayoutReflection* m_parameterBlockTypeLayout = nullptr;
198};
199
200class RootShaderObjectLayoutImpl : public ShaderObjectLayoutImpl
201{
202    typedef ShaderObjectLayoutImpl Super;
203
204public:
205    struct EntryPointInfo
206    {
207        RefPtr<ShaderObjectLayoutImpl> layout;
208
209        /// The offset for this entry point's parameters, relative to the starting offset for the
210        /// program
211        BindingOffset offset;
212    };
213
214    struct Builder : Super::Builder
215    {
216        Builder(
217            RendererBase* renderer,
218            slang::IComponentType* program,
219            slang::ProgramLayout* programLayout)
220            : Super::Builder(renderer, program->getSession())
221            , m_program(program)
222            , m_programLayout(programLayout)
223        {
224        }
225
226        Result build(RootShaderObjectLayoutImpl** outLayout);
227        void addGlobalParams(slang::VariableLayoutReflection* globalsLayout);
228        void addEntryPoint(
229            SlangStage stage,
230            ShaderObjectLayoutImpl* entryPointLayout,
231            slang::EntryPointLayout* slangEntryPoint);
232
233        slang::IComponentType* m_program;
234        slang::ProgramLayout* m_programLayout;
235        List<EntryPointInfo> m_entryPoints;
236    };
237
238    EntryPointInfo& getEntryPoint(Index index) { return m_entryPoints[index]; }
239
240    List<EntryPointInfo>& getEntryPoints() { return m_entryPoints; }
241
242    static Result create(
243        RendererBase* renderer,
244        slang::IComponentType* program,
245        slang::ProgramLayout* programLayout,
246        RootShaderObjectLayoutImpl** outLayout);
247
248    slang::IComponentType* getSlangProgram() const { return m_program; }
249    slang::ProgramLayout* getSlangProgramLayout() const { return m_programLayout; }
250
251protected:
252    Result _init(Builder const* builder);
253
254    ComPtr<slang::IComponentType> m_program;
255    slang::ProgramLayout* m_programLayout = nullptr;
256
257    List<EntryPointInfo> m_entryPoints;
258};
259
260} // namespace metal
261} // namespace gfx