yum-mirror/slang

Making it easier to work with shaders

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

Ellie Hermaszewskaformatf65d756bf

master
10.4 KiB280 linesraw
1// d3d11-helper-functions.h
2#pragma once
3
4#include "../../../source/core/slang-list.h"
5#include "d3d11-base.h"
6#include "slang-gfx.h"
7
8namespace gfx
9{
10
11using namespace Slang;
12
13namespace d3d11
14{
15/// Contextual data and operations required when binding shader objects to the pipeline state
16struct BindingContext
17{
18    // One key service that the `BindingContext` provides is abstracting over
19    // the difference between the D3D11 compute and graphics/rasteriation pipelines.
20    // D3D11 has distinct operations for, e.g., `CSSetShaderResources`
21    // for compute vs. `VSSetShaderResources` and `PSSetShaderResources`
22    // for rasterization.
23    //
24    // The context type provides simple operations for setting each class
25    // of resource/sampler, which will be overridden in derived types.
26    //
27    // TODO: These operations should really support binding multiple resources/samplers
28    // in one call, so that we can eventually make more efficient use of the API.
29    //
30    // TODO: We could reasonably also just store the bound resources into
31    // lcoal arrays like we are doing for UAVs, and remove the pipeline-specific
32    // virtual functions. However, doing so would seemingly eliminate any
33    // chance of avoiding redundant binding work when binding changes are
34    // made for a root shader object.
35    //
36    virtual void setCBV(UINT index, ID3D11Buffer* buffer) = 0;
37    virtual void setSRV(UINT index, ID3D11ShaderResourceView* srv) = 0;
38    virtual void setSampler(UINT index, ID3D11SamplerState* sampler) = 0;
39
40    // Unordered Access Views (UAVs) are a somewhat special case in that
41    // the D3D11 API requires them to all be set at once, rather than one
42    // at a time. To support this, we will keep a local array of the UAVs
43    // that have been bound (up to the maximum supported by D3D 11.0)
44    //
45    void setUAV(UINT index, ID3D11UnorderedAccessView* uav)
46    {
47        uavs[index] = uav;
48
49        // We will also track the total number of UAV slots that will
50        // need to be bound (including any gaps that might occur due
51        // to either explicit bindings or RTV bindings that conflict
52        // with the `u` registers for fragment shaders).
53        //
54        if (uavCount <= index)
55        {
56            uavCount = index + 1;
57        }
58    }
59
60    /// The values bound for any UAVs
61    ID3D11UnorderedAccessView* uavs[D3D11_PS_CS_UAV_REGISTER_COUNT];
62
63    /// The number of entries in `uavs` that need to be considered when binding to the pipeline
64    UINT uavCount = 0;
65
66    /// The D3D11 device that we are using for binding
67    DeviceImpl* device = nullptr;
68
69    /// The D3D11 device context that we are using for binding
70    ID3D11DeviceContext* context = nullptr;
71
72    /// Initialize a binding context for binding to the given `device` and `context`
73    BindingContext(DeviceImpl* device, ID3D11DeviceContext* context)
74        : device(device), context(context)
75    {
76        memset(uavs, 0, sizeof(uavs));
77    }
78};
79
80/// A `BindingContext` for binding to the compute pipeline
81struct ComputeBindingContext : BindingContext
82{
83    /// Initialize a binding context for binding to the given `device` and `context`
84    ComputeBindingContext(DeviceImpl* device, ID3D11DeviceContext* context)
85        : BindingContext(device, context)
86    {
87    }
88
89    void setCBV(UINT index, ID3D11Buffer* buffer) SLANG_OVERRIDE
90    {
91        context->CSSetConstantBuffers(index, 1, &buffer);
92    }
93
94    void setSRV(UINT index, ID3D11ShaderResourceView* srv) SLANG_OVERRIDE
95    {
96        context->CSSetShaderResources(index, 1, &srv);
97    }
98
99    void setSampler(UINT index, ID3D11SamplerState* sampler) SLANG_OVERRIDE
100    {
101        context->CSSetSamplers(index, 1, &sampler);
102    }
103};
104
105/// A `BindingContext` for binding to the graphics/rasterization pipeline
106struct GraphicsBindingContext : BindingContext
107{
108    /// Initialize a binding context for binding to the given `device` and `context`
109    GraphicsBindingContext(DeviceImpl* device, ID3D11DeviceContext* context)
110        : BindingContext(device, context)
111    {
112    }
113
114    // TODO: The operations here are only dealing with vertex and fragment
115    // shaders for now. We should eventually extend them to handle HS/DS/GS
116    // bindings. (We might want to skip those stages depending on whether
117    // the associated program uses them at all).
118    //
119    // TODO: If we support cases where different stages might use distinct
120    // entry-point parameters, we might need to support some modes where
121    // a "stage mask" is passed in that applies to the bindings.
122    //
123    void setCBV(UINT index, ID3D11Buffer* buffer) SLANG_OVERRIDE
124    {
125        context->VSSetConstantBuffers(index, 1, &buffer);
126        context->PSSetConstantBuffers(index, 1, &buffer);
127    }
128
129    void setSRV(UINT index, ID3D11ShaderResourceView* srv) SLANG_OVERRIDE
130    {
131        context->VSSetShaderResources(index, 1, &srv);
132        context->PSSetShaderResources(index, 1, &srv);
133    }
134
135    void setSampler(UINT index, ID3D11SamplerState* sampler) SLANG_OVERRIDE
136    {
137        context->VSSetSamplers(index, 1, &sampler);
138        context->PSSetSamplers(index, 1, &sampler);
139    }
140};
141
142// In order to bind shader parameters to the correct locations, we need to
143// be able to describe those locations. Most shader parameters will
144// only consume a single type of D3D11-visible regsiter (e.g., a `t`
145// register for a txture, or an `s` register for a sampler), and scalar
146// integers suffice for these cases.
147//
148// In more complex cases we might be binding an entire "sub-object" like
149// a parameter block, an entry point, etc. For the general case, we need
150// to be able to represent a composite offset that includes offsets for
151// each of the register classes known to D3D11.
152
153/// A "simple" binding offset that records an offset in CBV/SRV/UAV/Sampler slots
154struct SimpleBindingOffset
155{
156    uint32_t cbv = 0;
157    uint32_t srv = 0;
158    uint32_t uav = 0;
159    uint32_t sampler = 0;
160
161    /// Create a default (zero) offset
162    SimpleBindingOffset() {}
163
164    /// Create an offset based on offset information in the given Slang `varLayout`
165    SimpleBindingOffset(slang::VariableLayoutReflection* varLayout)
166    {
167        if (varLayout)
168        {
169            cbv = (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER);
170            srv = (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE);
171            uav = (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS);
172            sampler = (uint32_t)varLayout->getOffset(SLANG_PARAMETER_CATEGORY_SAMPLER_STATE);
173        }
174    }
175
176    /// Create an offset based on size/stride information in the given Slang `typeLayout`
177    SimpleBindingOffset(slang::TypeLayoutReflection* typeLayout)
178    {
179        if (typeLayout)
180        {
181            cbv = (uint32_t)typeLayout->getSize(SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER);
182            srv = (uint32_t)typeLayout->getSize(SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE);
183            uav = (uint32_t)typeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS);
184            sampler = (uint32_t)typeLayout->getSize(SLANG_PARAMETER_CATEGORY_SAMPLER_STATE);
185        }
186    }
187
188    /// Add any values in the given `offset`
189    void operator+=(SimpleBindingOffset const& offset)
190    {
191        cbv += offset.cbv;
192        srv += offset.srv;
193        uav += offset.uav;
194        sampler += offset.sampler;
195    }
196};
197
198// While a "simple" binding offset representation will work in many cases,
199// once we need to deal with layout for programs with interface-type parameters
200// that have been statically specialized, we also need to track the offset
201// for where to bind any "pending" data that arises from the process of static
202// specialization.
203//
204// In order to conveniently track both the "primary" and "pending" offset information,
205// we will define a more complete `BindingOffset` type that combines simple
206// binding offsets for the primary and pending parts.
207
208/// A representation of the offset at which to bind a shader parameter or sub-object
209struct BindingOffset : SimpleBindingOffset
210{
211    // Offsets for "primary" data are stored directly in the `BindingOffset`
212    // via the inheritance from `SimpleBindingOffset`.
213
214    /// Offset for any "pending" data
215    SimpleBindingOffset pending;
216
217    /// Create a default (zero) offset
218    BindingOffset() {}
219
220    /// Create an offset from a simple offset
221    explicit BindingOffset(SimpleBindingOffset const& offset)
222        : SimpleBindingOffset(offset)
223    {
224    }
225
226    /// Create an offset based on offset information in the given Slang `varLayout`
227    BindingOffset(slang::VariableLayoutReflection* varLayout)
228        : SimpleBindingOffset(varLayout), pending(varLayout->getPendingDataLayout())
229    {
230    }
231
232    /// Create an offset based on size/stride information in the given Slang `typeLayout`
233    BindingOffset(slang::TypeLayoutReflection* typeLayout)
234        : SimpleBindingOffset(typeLayout), pending(typeLayout->getPendingDataTypeLayout())
235    {
236    }
237
238    /// Add any values in the given `offset`
239    void operator+=(SimpleBindingOffset const& offset) { SimpleBindingOffset::operator+=(offset); }
240
241    /// Add any values in the given `offset`
242    void operator+=(BindingOffset const& offset)
243    {
244        SimpleBindingOffset::operator+=(offset);
245        pending += offset.pending;
246    }
247};
248
249bool isSupportedNVAPIOp(IUnknown* dev, uint32_t op);
250
251D3D11_BIND_FLAG calcResourceFlag(ResourceState state);
252int _calcResourceBindFlags(ResourceStateSet allowedStates);
253int _calcResourceAccessFlags(MemoryType memType);
254
255D3D11_FILTER_TYPE translateFilterMode(TextureFilteringMode mode);
256D3D11_FILTER_REDUCTION_TYPE translateFilterReduction(TextureReductionOp op);
257D3D11_TEXTURE_ADDRESS_MODE translateAddressingMode(TextureAddressingMode mode);
258D3D11_COMPARISON_FUNC translateComparisonFunc(ComparisonFunc func);
259
260D3D11_STENCIL_OP translateStencilOp(StencilOp op);
261D3D11_FILL_MODE translateFillMode(FillMode mode);
262D3D11_CULL_MODE translateCullMode(CullMode mode);
263bool isBlendDisabled(AspectBlendDesc const& desc);
264bool isBlendDisabled(TargetBlendDesc const& desc);
265D3D11_BLEND_OP translateBlendOp(BlendOp op);
266D3D11_BLEND translateBlendFactor(BlendFactor factor);
267D3D11_COLOR_WRITE_ENABLE translateRenderTargetWriteMask(RenderTargetWriteMaskT mask);
268
269void initSrvDesc(
270    IResource::Type resourceType,
271    const ITextureResource::Desc& textureDesc,
272    DXGI_FORMAT pixelFormat,
273    D3D11_SHADER_RESOURCE_VIEW_DESC& descOut);
274} // namespace d3d11
275
276Result SLANG_MCALL getD3D11Adapters(List<AdapterInfo>& outAdapters);
277
278Result SLANG_MCALL createD3D11Device(const IDevice::Desc* desc, IDevice** outDevice);
279
280} // namespace gfx