yum-mirror/slang

Making it easier to work with shaders

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

Ellie Hermaszewskaformatf65d756bf

master
10.1 KiB301 linesraw
1// d3d12-shader-object.h
2#pragma once
3
4#include "d3d12-base.h"
5#include "d3d12-helper-functions.h"
6#include "d3d12-submitter.h"
7
8namespace gfx
9{
10namespace d3d12
11{
12
13using namespace Slang;
14
15struct DescriptorTable
16{
17    DescriptorHeapReference m_heap;
18    uint32_t m_offset = 0;
19    uint32_t m_count = 0;
20
21    SLANG_FORCE_INLINE uint32_t getDescriptorCount() const { return m_count; }
22
23    /// Get the GPU handle at the specified index
24    SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle(uint32_t index = 0) const
25    {
26        SLANG_ASSERT(index < getDescriptorCount());
27        return m_heap.getGpuHandle(m_offset + index);
28    }
29
30    /// Get the CPU handle at the specified index
31    SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle(uint32_t index = 0) const
32    {
33        SLANG_ASSERT(index < getDescriptorCount());
34        return m_heap.getCpuHandle(m_offset + index);
35    }
36
37    void freeIfSupported()
38    {
39        if (m_count)
40        {
41            m_heap.freeIfSupported(m_offset, m_count);
42            m_offset = 0;
43            m_count = 0;
44        }
45    }
46
47    bool allocate(uint32_t count)
48    {
49        auto allocatedOffset = m_heap.allocate(count);
50        if (allocatedOffset == -1)
51            return false;
52        m_offset = allocatedOffset;
53        m_count = count;
54        return true;
55    }
56
57    bool allocate(DescriptorHeapReference heap, uint32_t count)
58    {
59        auto allocatedOffset = heap.allocate(count);
60        if (allocatedOffset == -1)
61            return false;
62        m_heap = heap;
63        m_offset = allocatedOffset;
64        m_count = count;
65        return true;
66    }
67};
68
69/// A reprsentation of an allocated descriptor set, consisting of an option resource table and
70/// an optional sampler table
71struct DescriptorSet
72{
73    DescriptorTable resourceTable;
74    DescriptorTable samplerTable;
75
76    void freeIfSupported()
77    {
78        resourceTable.freeIfSupported();
79        samplerTable.freeIfSupported();
80    }
81};
82
83class ShaderObjectImpl
84    : public ShaderObjectBaseImpl<ShaderObjectImpl, ShaderObjectLayoutImpl, SimpleShaderObjectData>
85{
86    typedef ShaderObjectBaseImpl<ShaderObjectImpl, ShaderObjectLayoutImpl, SimpleShaderObjectData>
87        Super;
88
89public:
90    static Result create(
91        DeviceImpl* device,
92        ShaderObjectLayoutImpl* layout,
93        ShaderObjectImpl** outShaderObject);
94
95    ~ShaderObjectImpl();
96
97    RendererBase* getDevice() { return m_device.get(); }
98
99    virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() override;
100
101    virtual SLANG_NO_THROW Result SLANG_MCALL
102    getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) override;
103
104    virtual SLANG_NO_THROW const void* SLANG_MCALL getRawData() override;
105
106    virtual SLANG_NO_THROW Size SLANG_MCALL getSize() override;
107
108    // TODO: What to do with size_t?
109    virtual SLANG_NO_THROW Result SLANG_MCALL
110    setData(ShaderOffset const& inOffset, void const* data, size_t inSize) override;
111    virtual SLANG_NO_THROW Result SLANG_MCALL
112    setObject(ShaderOffset const& offset, IShaderObject* object) override;
113
114    virtual SLANG_NO_THROW Result SLANG_MCALL
115    setResource(ShaderOffset const& offset, IResourceView* resourceView) override;
116
117    virtual SLANG_NO_THROW Result SLANG_MCALL
118    setSampler(ShaderOffset const& offset, ISamplerState* sampler) override;
119
120    virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler(
121        ShaderOffset const& offset,
122        IResourceView* textureView,
123        ISamplerState* sampler) override;
124
125protected:
126    Result init(
127        DeviceImpl* device,
128        ShaderObjectLayoutImpl* layout,
129        DescriptorHeapReference viewHeap,
130        DescriptorHeapReference samplerHeap);
131
132    /// Write the uniform/ordinary data of this object into the given `dest` buffer at the given
133    /// `offset`
134    Result _writeOrdinaryData(
135        PipelineCommandEncoder* encoder,
136        BufferResourceImpl* buffer,
137        Offset offset,
138        Size destSize,
139        ShaderObjectLayoutImpl* specializedLayout);
140
141    bool shouldAllocateConstantBuffer(TransientResourceHeapImpl* transientHeap);
142
143    /// Ensure that the `m_ordinaryDataBuffer` has been created, if it is needed
144    Result _ensureOrdinaryDataBufferCreatedIfNeeded(
145        PipelineCommandEncoder* encoder,
146        ShaderObjectLayoutImpl* specializedLayout);
147
148public:
149    void updateSubObjectsRecursive();
150    /// Prepare to bind this object as a parameter block.
151    ///
152    /// This involves allocating and binding any descriptor tables necessary
153    /// to to store the state of the object. The function returns a descriptor
154    /// set formed from any table(s) allocated. In addition, the `ioOffset`
155    /// parameter will be adjusted to be correct for binding values into
156    /// the resulting descriptor set.
157    ///
158    /// Returns:
159    ///   SLANG_OK when successful,
160    ///   SLANG_E_OUT_OF_MEMORY when descriptor heap is full.
161    ///
162    Result prepareToBindAsParameterBlock(
163        BindingContext* context,
164        BindingOffset& ioOffset,
165        ShaderObjectLayoutImpl* specializedLayout,
166        DescriptorSet& outDescriptorSet);
167
168    bool checkIfCachedDescriptorSetIsValidRecursive(BindingContext* context);
169
170    /// Bind this object as a `ParameterBlock<X>`
171    Result bindAsParameterBlock(
172        BindingContext* context,
173        BindingOffset const& offset,
174        ShaderObjectLayoutImpl* specializedLayout);
175
176    /// Bind this object as a `ConstantBuffer<X>`
177    Result bindAsConstantBuffer(
178        BindingContext* context,
179        DescriptorSet const& descriptorSet,
180        BindingOffset const& offset,
181        ShaderObjectLayoutImpl* specializedLayout);
182
183    /// Bind this object as a value (for an interface-type parameter)
184    Result bindAsValue(
185        BindingContext* context,
186        DescriptorSet const& descriptorSet,
187        BindingOffset const& offset,
188        ShaderObjectLayoutImpl* specializedLayout);
189
190    /// Shared logic for `bindAsConstantBuffer()` and `bindAsValue()`
191    Result _bindImpl(
192        BindingContext* context,
193        DescriptorSet const& descriptorSet,
194        BindingOffset const& offset,
195        ShaderObjectLayoutImpl* specializedLayout);
196
197    Result bindRootArguments(BindingContext* context, uint32_t& index);
198    /// A CPU-memory descriptor set holding any descriptors used to represent the
199    /// resources/samplers in this object's state
200    DescriptorSet m_descriptorSet;
201    /// A cached descriptor set on GPU heap.
202    DescriptorSet m_cachedGPUDescriptorSet;
203
204    ShortList<RefPtr<Resource>, 8> m_boundResources;
205    ShortList<RefPtr<Resource>, 8> m_boundCounterResources;
206    List<D3D12_GPU_VIRTUAL_ADDRESS> m_rootArguments;
207    /// A constant buffer used to stored ordinary data for this object
208    /// and existential-type sub-objects.
209    ///
210    /// Allocated from transient heap on demand with `_createOrdinaryDataBufferIfNeeded()`
211    IBufferResource* m_constantBufferWeakPtr = nullptr;
212    Offset m_constantBufferOffset = 0;
213    Size m_constantBufferSize = 0;
214
215    /// Dirty bit tracking whether the constant buffer needs to be updated.
216    bool m_isConstantBufferDirty = true;
217    /// The transient heap from which the constant buffer and descriptor set is allocated.
218    TransientResourceHeapImpl* m_cachedTransientHeap;
219    /// The version of the transient heap when the constant buffer and descriptor set is
220    /// allocated.
221    uint64_t m_cachedTransientHeapVersion;
222
223    /// Whether this shader object is allowed to be mutable.
224    bool m_isMutable = false;
225    /// The version of a mutable shader object.
226    uint32_t m_version = 0;
227    /// The version of this mutable shader object when the gpu descriptor table is cached.
228    uint32_t m_cachedGPUDescriptorSetVersion = -1;
229    /// The versions of bound subobjects.
230    List<uint32_t> m_subObjectVersions;
231
232    /// Get the layout of this shader object with specialization arguments considered
233    ///
234    /// This operation should only be called after the shader object has been
235    /// fully filled in and finalized.
236    ///
237    Result getSpecializedLayout(ShaderObjectLayoutImpl** outLayout);
238
239    /// Create the layout for this shader object with specialization arguments considered
240    ///
241    /// This operation is virtual so that it can be customized by `RootShaderObject`.
242    ///
243    virtual Result _createSpecializedLayout(ShaderObjectLayoutImpl** outLayout);
244
245    RefPtr<ShaderObjectLayoutImpl> m_specializedLayout;
246};
247
248class RootShaderObjectImpl : public ShaderObjectImpl
249{
250    typedef ShaderObjectImpl Super;
251
252public:
253    // Override default reference counting behavior to disable lifetime management via ComPtr.
254    // Root objects are managed by command buffer and does not need to be freed by the user.
255    SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return 1; }
256    SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return 1; }
257
258public:
259    RootShaderObjectLayoutImpl* getLayout();
260
261    virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() override;
262    virtual SLANG_NO_THROW SlangResult SLANG_MCALL
263    getEntryPoint(GfxIndex index, IShaderObject** outEntryPoint) override;
264    virtual Result collectSpecializationArgs(ExtendedShaderObjectTypeList& args) override;
265    virtual SLANG_NO_THROW Result SLANG_MCALL
266    copyFrom(IShaderObject* object, ITransientResourceHeap* transientHeap) override;
267
268public:
269    Result bindAsRoot(BindingContext* context, RootShaderObjectLayoutImpl* specializedLayout);
270
271public:
272    Result init(DeviceImpl* device) { return SLANG_OK; }
273
274    Result resetImpl(
275        DeviceImpl* device,
276        RootShaderObjectLayoutImpl* layout,
277        DescriptorHeapReference viewHeap,
278        DescriptorHeapReference samplerHeap,
279        bool isMutable);
280
281    Result reset(
282        DeviceImpl* device,
283        RootShaderObjectLayoutImpl* layout,
284        TransientResourceHeapImpl* heap);
285
286protected:
287    virtual Result _createSpecializedLayout(ShaderObjectLayoutImpl** outLayout) override;
288
289    List<RefPtr<ShaderObjectImpl>> m_entryPoints;
290};
291
292class MutableRootShaderObjectImpl : public RootShaderObjectImpl
293{
294public:
295    // Enable reference counting.
296    SLANG_NO_THROW uint32_t SLANG_MCALL addRef() override { return ShaderObjectBase::addRef(); }
297    SLANG_NO_THROW uint32_t SLANG_MCALL release() override { return ShaderObjectBase::release(); }
298};
299
300} // namespace d3d12
301} // namespace gfx