yum-mirror/slang

Making it easier to work with shaders

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

Ellie HermaszewskaMove switch statement bodies to their own lines (#5493)b118451e3

master
12.2 KiB343 linesraw
1// d3d11-shader-object-layout.cpp
2#include "d3d11-shader-object-layout.h"
3
4namespace gfx
5{
6
7using namespace Slang;
8
9namespace d3d11
10{
11
12ShaderObjectLayoutImpl::SubObjectRangeOffset::SubObjectRangeOffset(
13    slang::VariableLayoutReflection* varLayout)
14    : BindingOffset(varLayout)
15{
16    if (auto pendingLayout = varLayout->getPendingDataLayout())
17    {
18        pendingOrdinaryData = (uint32_t)pendingLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNIFORM);
19    }
20}
21
22ShaderObjectLayoutImpl::SubObjectRangeStride::SubObjectRangeStride(
23    slang::TypeLayoutReflection* typeLayout)
24    : BindingOffset(typeLayout)
25{
26    if (auto pendingLayout = typeLayout->getPendingDataTypeLayout())
27    {
28        pendingOrdinaryData = (uint32_t)typeLayout->getStride();
29    }
30}
31
32Result ShaderObjectLayoutImpl::Builder::setElementTypeLayout(
33    slang::TypeLayoutReflection* typeLayout)
34{
35    typeLayout = _unwrapParameterGroups(typeLayout, m_containerType);
36
37    m_elementTypeLayout = typeLayout;
38
39    m_totalOrdinaryDataSize = (uint32_t)typeLayout->getSize();
40
41    // Compute the binding ranges that are used to store
42    // the logical contents of the object in memory.
43
44    SlangInt bindingRangeCount = typeLayout->getBindingRangeCount();
45    for (SlangInt r = 0; r < bindingRangeCount; ++r)
46    {
47        slang::BindingType slangBindingType = typeLayout->getBindingRangeType(r);
48        SlangInt count = typeLayout->getBindingRangeBindingCount(r);
49        slang::TypeLayoutReflection* slangLeafTypeLayout =
50            typeLayout->getBindingRangeLeafTypeLayout(r);
51
52        BindingRangeInfo bindingRangeInfo;
53        bindingRangeInfo.bindingType = slangBindingType;
54        bindingRangeInfo.count = count;
55        bindingRangeInfo.isSpecializable = typeLayout->isBindingRangeSpecializable(r);
56        switch (slangBindingType)
57        {
58        case slang::BindingType::ConstantBuffer:
59        case slang::BindingType::ParameterBlock:
60        case slang::BindingType::ExistentialValue:
61            bindingRangeInfo.baseIndex = m_subObjectCount;
62            bindingRangeInfo.subObjectIndex = m_subObjectCount;
63            m_subObjectCount += count;
64            break;
65        case slang::BindingType::RawBuffer:
66        case slang::BindingType::MutableRawBuffer:
67            if (slangLeafTypeLayout->getType()->getElementType() != nullptr)
68            {
69                // A structured buffer occupies both a resource slot and
70                // a sub-object slot.
71                bindingRangeInfo.subObjectIndex = m_subObjectCount;
72                m_subObjectCount += count;
73            }
74            if (slangBindingType == slang::BindingType::RawBuffer)
75            {
76                bindingRangeInfo.baseIndex = m_srvCount;
77                m_srvCount += count;
78                m_srvRanges.add(r);
79            }
80            else
81            {
82                bindingRangeInfo.baseIndex = m_uavCount;
83                m_uavCount += count;
84                m_uavRanges.add(r);
85            }
86            break;
87        case slang::BindingType::Sampler:
88            bindingRangeInfo.baseIndex = m_samplerCount;
89            m_samplerCount += count;
90            m_samplerRanges.add(r);
91            break;
92
93        case slang::BindingType::CombinedTextureSampler:
94            break;
95        case slang::BindingType::MutableTexture:
96        case slang::BindingType::MutableTypedBuffer:
97            bindingRangeInfo.baseIndex = m_uavCount;
98            m_uavCount += count;
99            m_uavRanges.add(r);
100            break;
101
102        case slang::BindingType::VaryingInput:
103            break;
104
105        case slang::BindingType::VaryingOutput:
106            break;
107
108        default:
109            bindingRangeInfo.baseIndex = m_srvCount;
110            m_srvCount += count;
111            m_srvRanges.add(r);
112            break;
113        }
114
115        // We'd like to extract the information on the D3D11 shader
116        // register that this range should bind into.
117        //
118        // A binding range represents a logical member of the shader
119        // object type, and it may encompass zero or more *descriptor
120        // ranges* that describe how it is physically bound to pipeline
121        // state.
122        //
123        // If the current bindign range is backed by at least one descriptor
124        // range then we can query the register offset of that descriptor
125        // range. We expect that in the common case there will be exactly
126        // one descriptor range, and we can extract the information easily.
127        //
128        // TODO: we might eventually need to special-case our handling
129        // of combined texture-sampler ranges since they will need to
130        // store two different offsets.
131        //
132        if (typeLayout->getBindingRangeDescriptorRangeCount(r) != 0)
133        {
134            // The Slang reflection information organizes the descriptor ranges
135            // into "descriptor sets" but D3D11 has no notion like that so we
136            // expect all ranges belong to a single set.
137            //
138            SlangInt descriptorSetIndex = typeLayout->getBindingRangeDescriptorSetIndex(r);
139            SLANG_ASSERT(descriptorSetIndex == 0);
140
141            SlangInt descriptorRangeIndex = typeLayout->getBindingRangeFirstDescriptorRangeIndex(r);
142            auto registerOffset = typeLayout->getDescriptorSetDescriptorRangeIndexOffset(
143                descriptorSetIndex,
144                descriptorRangeIndex);
145
146            bindingRangeInfo.registerOffset = (uint32_t)registerOffset;
147        }
148
149        m_bindingRanges.add(bindingRangeInfo);
150    }
151
152    SlangInt subObjectRangeCount = typeLayout->getSubObjectRangeCount();
153    for (SlangInt r = 0; r < subObjectRangeCount; ++r)
154    {
155        SlangInt bindingRangeIndex = typeLayout->getSubObjectRangeBindingRangeIndex(r);
156        auto& bindingRange = m_bindingRanges[bindingRangeIndex];
157
158        auto slangBindingType = typeLayout->getBindingRangeType(bindingRangeIndex);
159        slang::TypeLayoutReflection* slangLeafTypeLayout =
160            typeLayout->getBindingRangeLeafTypeLayout(bindingRangeIndex);
161
162        SubObjectRangeInfo subObjectRange;
163        subObjectRange.bindingRangeIndex = bindingRangeIndex;
164
165        // We will use Slang reflection information to extract the offset and stride
166        // information for each sub-object range.
167        //
168        subObjectRange.offset = SubObjectRangeOffset(typeLayout->getSubObjectRangeOffset(r));
169        subObjectRange.stride = SubObjectRangeStride(slangLeafTypeLayout);
170
171        // A sub-object range can either represent a sub-object of a known
172        // type, like a `ConstantBuffer<Foo>` or `ParameterBlock<Foo>`
173        // *or* it can represent a sub-object of some existential type (e.g., `IBar`).
174        //
175        RefPtr<ShaderObjectLayoutImpl> subObjectLayout;
176        switch (slangBindingType)
177        {
178        default:
179            {
180                // In the case of `ConstantBuffer<X>` or `ParameterBlock<X>`
181                // we can construct a layout from the element type directly.
182                //
183                auto elementTypeLayout = slangLeafTypeLayout->getElementTypeLayout();
184                createForElementType(
185                    m_renderer,
186                    m_session,
187                    elementTypeLayout,
188                    subObjectLayout.writeRef());
189            }
190            break;
191
192        case slang::BindingType::ExistentialValue:
193            // In the case of an interface-type sub-object range, we can only
194            // construct a layout if we have static specialization information
195            // that tells us what type we expect to find in that range.
196            //
197            // The static specialization information is expected to take the
198            // form of a "pending" type layotu attached to the interface type
199            // of the leaf type layout.
200            //
201            if (auto pendingTypeLayout = slangLeafTypeLayout->getPendingDataTypeLayout())
202            {
203                createForElementType(
204                    m_renderer,
205                    m_session,
206                    pendingTypeLayout,
207                    subObjectLayout.writeRef());
208
209                // An interface-type range that includes ordinary data can
210                // increase the size of the ordinary data buffer we need to
211                // allocate for the parent object.
212                //
213                uint32_t ordinaryDataEnd =
214                    subObjectRange.offset.pendingOrdinaryData +
215                    (uint32_t)bindingRange.count * subObjectRange.stride.pendingOrdinaryData;
216
217                if (ordinaryDataEnd > m_totalOrdinaryDataSize)
218                {
219                    m_totalOrdinaryDataSize = ordinaryDataEnd;
220                }
221            }
222        }
223        subObjectRange.layout = subObjectLayout;
224
225        m_subObjectRanges.add(subObjectRange);
226    }
227    return SLANG_OK;
228}
229
230SlangResult ShaderObjectLayoutImpl::Builder::build(ShaderObjectLayoutImpl** outLayout)
231{
232    auto layout = RefPtr<ShaderObjectLayoutImpl>(new ShaderObjectLayoutImpl());
233    SLANG_RETURN_ON_FAIL(layout->_init(this));
234
235    returnRefPtrMove(outLayout, layout);
236    return SLANG_OK;
237}
238
239Result ShaderObjectLayoutImpl::createForElementType(
240    RendererBase* renderer,
241    slang::ISession* session,
242    slang::TypeLayoutReflection* elementType,
243    ShaderObjectLayoutImpl** outLayout)
244{
245    Builder builder(renderer, session);
246    builder.setElementTypeLayout(elementType);
247    return builder.build(outLayout);
248}
249
250Result ShaderObjectLayoutImpl::_init(Builder const* builder)
251{
252    auto renderer = builder->m_renderer;
253
254    initBase(renderer, builder->m_session, builder->m_elementTypeLayout);
255
256    m_bindingRanges = builder->m_bindingRanges;
257    m_srvRanges = builder->m_srvRanges;
258    m_uavRanges = builder->m_uavRanges;
259    m_samplerRanges = builder->m_samplerRanges;
260
261    m_srvCount = builder->m_srvCount;
262    m_samplerCount = builder->m_samplerCount;
263    m_uavCount = builder->m_uavCount;
264    m_subObjectCount = builder->m_subObjectCount;
265    m_subObjectRanges = builder->m_subObjectRanges;
266
267    m_totalOrdinaryDataSize = builder->m_totalOrdinaryDataSize;
268
269    m_containerType = builder->m_containerType;
270    return SLANG_OK;
271}
272
273Result RootShaderObjectLayoutImpl::Builder::build(RootShaderObjectLayoutImpl** outLayout)
274{
275    RefPtr<RootShaderObjectLayoutImpl> layout = new RootShaderObjectLayoutImpl();
276    SLANG_RETURN_ON_FAIL(layout->_init(this));
277
278    returnRefPtrMove(outLayout, layout);
279    return SLANG_OK;
280}
281
282void RootShaderObjectLayoutImpl::Builder::addGlobalParams(
283    slang::VariableLayoutReflection* globalsLayout)
284{
285    setElementTypeLayout(globalsLayout->getTypeLayout());
286    m_pendingDataOffset = BindingOffset(globalsLayout).pending;
287}
288
289void RootShaderObjectLayoutImpl::Builder::addEntryPoint(
290    SlangStage stage,
291    ShaderObjectLayoutImpl* entryPointLayout,
292    slang::EntryPointLayout* slangEntryPoint)
293{
294    EntryPointInfo info;
295    info.layout = entryPointLayout;
296    info.offset = BindingOffset(slangEntryPoint->getVarLayout());
297    m_entryPoints.add(info);
298}
299
300Result RootShaderObjectLayoutImpl::create(
301    RendererBase* renderer,
302    slang::IComponentType* program,
303    slang::ProgramLayout* programLayout,
304    RootShaderObjectLayoutImpl** outLayout)
305{
306    RootShaderObjectLayoutImpl::Builder builder(renderer, program, programLayout);
307    builder.addGlobalParams(programLayout->getGlobalParamsVarLayout());
308
309    SlangInt entryPointCount = programLayout->getEntryPointCount();
310    for (SlangInt e = 0; e < entryPointCount; ++e)
311    {
312        auto slangEntryPoint = programLayout->getEntryPointByIndex(e);
313        RefPtr<ShaderObjectLayoutImpl> entryPointLayout;
314        SLANG_RETURN_ON_FAIL(ShaderObjectLayoutImpl::createForElementType(
315            renderer,
316            program->getSession(),
317            slangEntryPoint->getTypeLayout(),
318            entryPointLayout.writeRef()));
319        builder.addEntryPoint(slangEntryPoint->getStage(), entryPointLayout, slangEntryPoint);
320    }
321
322    SLANG_RETURN_ON_FAIL(builder.build(outLayout));
323
324    return SLANG_OK;
325}
326
327Result RootShaderObjectLayoutImpl::_init(Builder const* builder)
328{
329    auto renderer = builder->m_renderer;
330
331    SLANG_RETURN_ON_FAIL(Super::_init(builder));
332
333    m_program = builder->m_program;
334    m_programLayout = builder->m_programLayout;
335    m_entryPoints = builder->m_entryPoints;
336    m_pendingDataOffset = builder->m_pendingDataOffset;
337    m_slangSession = m_program->getSession();
338
339    return SLANG_OK;
340}
341
342} // namespace d3d11
343} // namespace gfx