1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_IMAGING_HD_ST_RESOURCE_BINDER_H
25 #define PXR_IMAGING_HD_ST_RESOURCE_BINDER_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/imaging/hdSt/api.h"
29 #include "pxr/imaging/hd/version.h"
30 
31 #include "pxr/imaging/hd/binding.h"
32 #include "pxr/imaging/hgi/handle.h"
33 #include "pxr/base/tf/token.h"
34 #include "pxr/base/tf/stl.h"
35 #include "pxr/base/tf/staticTokens.h"
36 
37 #include <memory>
38 
39 PXR_NAMESPACE_OPEN_SCOPE
40 
41 
42 class HdStDrawItem;
43 
44 using HdStBufferResourceSharedPtr =
45     std::shared_ptr<class HdStBufferResource>;
46 using HdStBufferArrayRangeSharedPtr =
47     std::shared_ptr<class HdStBufferArrayRange>;
48 
49 using HdStShaderCodeSharedPtr = std::shared_ptr<class HdStShaderCode>;
50 using HdStShaderCodeSharedPtrVector = std::vector<HdStShaderCodeSharedPtr>;
51 using HdBindingRequestVector = std::vector<class HdBindingRequest>;
52 
53 using HgiTextureHandle = HgiHandle<class HgiTexture>;
54 using HgiSamplerHandle = HgiHandle<class HgiSampler>;
55 using HgiShaderProgramHandle = HgiHandle<class HgiShaderProgram>;
56 
57 /// Suffixes appended to material param names for a binding name.
58 ///
59 #define HDST_RESOURCE_BINDING_SUFFIX_TOKENS     \
60     ((fallback, "_fallback"))                   \
61     ((samplingTransform, "_samplingTransform")) \
62     ((layout, "_layout"))                       \
63     ((texture, "_texture"))                     \
64     ((valid, "_valid"))
65 
66 TF_DECLARE_PUBLIC_TOKENS(HdSt_ResourceBindingSuffixTokens,
67                          HDST_RESOURCE_BINDING_SUFFIX_TOKENS);
68 
69 /// \class HdSt_ResourceBinder
70 ///
71 /// A helper class to maintain all vertex/buffer/uniform binding points to be
72 /// used for both codegen time and rendering time.
73 ///
74 /// Storm uses 6 different types of coherent buffers.
75 ///
76 /// 1. Constant buffer
77 ///   constant primvars, which is uniform for all instances/elements/vertices.
78 ///     ex. transform, object color
79 //    [SSBO, BindlessUniform]
80 ///
81 /// 2. Instance buffer
82 ///   instance primvars, one-per-instance.
83 ///     ex. translate/scale/rotate, instanceIndices
84 //    [SSBO, BindlessUniform]
85 ///
86 /// 3. Element buffer
87 ///   element primvars. one-per-element (face, line).
88 ///     ex. face color
89 ///   [SSBO]
90 ///
91 /// 4. Vertex buffer
92 ///   vertex primvars. one-per-vertex.
93 ///     ex. positions, normals, vertex color
94 ///   [VertexAttribute]
95 ///
96 /// 5. Index buffer
97 ///   points/triangles/quads/lines/patches indices.
98 ///     ex. indices, primitive param.
99 ///   [IndexAttribute, SSBO]
100 ///
101 /// 6. DrawIndex buffer
102 ///   draw command data. one-per-drawitem (gl_DrawID equivalent)
103 ///     ex. drawing coordinate, instance counts
104 ///   [VertexAttribute]
105 ///
106 ///
107 ///
108 /// For instance index indirection, three bindings are needed:
109 ///
110 ///    +-----------------------------------------+
111 ///    |  instance indices buffer resource       | <-- <arrayBinding>
112 ///    +-----------------------------------------+
113 ///    |* culled instance indices buffer resource| <-- <culledArrayBinding>
114 ///    +-----------------------------------------+  (bindless uniform
115 ///                  ^   ^      ^                      or SSBO)
116 /// DrawCalls +---+  |   |      |
117 ///          0|   |---   |      |
118 ///           +---+      |      |
119 ///          1|   |-------      |
120 ///           +---+             |
121 ///          2|   |--------------
122 ///           +---+
123 ///             ^
124 ///             --- <baseBinding>
125 ///                  (immediate:uniform, indirect:vertex attrib)
126 ///
127 /// (*) GPU frustum culling shader shuffles instance indices into
128 ///     culled indices buffer.
129 ///
130 ///
131 /// HdSt_ResourceBinder also takes custom bindings.
132 ///
133 /// Custom bindings are used to manage bindable resources for
134 /// glsl shader code which is not itself generated by codegen.
135 ///
136 /// For each custom binding, codegen will emit a binding definition
137 /// that can be used as the value of a glsl \a binding or
138 /// \a location layout qualifier.
139 ///
140 /// e.g. Adding a custom binding of 2 for "paramsBuffer", will
141 /// cause codegen to emit the definition:
142 /// \code
143 /// #define paramsBuffer_Binding 2
144 /// \endcode
145 /// which can be used in a custom glsl resource declaration as:
146 /// \code
147 /// layout (binding = paramsBuffer_Binding) buffer ParamsBuffer { ... };
148 /// \endcode
149 ///
150 class HdSt_ResourceBinder {
151 public:
152     /// binding metadata for codegen
153     class MetaData {
154     public:
MetaData()155         MetaData() : instancerNumLevels(0) {}
156 
157         typedef size_t ID;
158         /// Returns the hash value of this metadata.
159         HDST_API
160         ID ComputeHash() const;
161 
162         // -------------------------------------------------------------------
163         // for a primvar in interleaved buffer array (Constant, ShaderData)
164         struct StructEntry {
StructEntryStructEntry165             StructEntry(TfToken const &name,
166                         TfToken const &dataType,
167                         int offset, int arraySize)
168                 : name(name)
169                 , dataType(dataType)
170                 , offset(offset)
171                 , arraySize(arraySize)
172             {}
173 
174             TfToken name;
175             TfToken dataType;
176             int offset;
177             int arraySize;
178 
179             bool operator < (StructEntry const &other) const {
180                 return offset < other.offset;
181             }
182         };
183         struct StructBlock {
StructBlockStructBlock184             StructBlock(TfToken const &name)
185                 : blockName(name) {}
186             TfToken blockName;
187             std::vector<StructEntry> entries;
188         };
189         typedef std::map<HdBinding, StructBlock> StructBlockBinding;
190 
191         // -------------------------------------------------------------------
192         // for a primvar in non-interleaved buffer array (Vertex, Element, ...)
193         struct Primvar {
PrimvarPrimvar194             Primvar() {}
PrimvarPrimvar195             Primvar(TfToken const &name, TfToken const &dataType)
196                 : name(name), dataType(dataType) {}
197             TfToken name;
198             TfToken dataType;
199         };
200         typedef std::map<HdBinding, Primvar> PrimvarBinding;
201 
202         // -------------------------------------------------------------------
203         // for a face-varying primvar in non-interleaved buffer array
204         struct FvarPrimvar : Primvar {
FvarPrimvarFvarPrimvar205             FvarPrimvar() : channel(0) {}
FvarPrimvarFvarPrimvar206             FvarPrimvar(TfToken const &name, TfToken const &dataType,
207                         int channel)
208                 : Primvar(name, dataType), channel(channel) {}
209             int channel;
210         };
211         typedef std::map<HdBinding, FvarPrimvar> FvarPrimvarBinding;
212 
213         // -------------------------------------------------------------------
214         // for instance primvars
215         struct NestedPrimvar {
NestedPrimvarNestedPrimvar216             NestedPrimvar() {}
NestedPrimvarNestedPrimvar217             NestedPrimvar(TfToken const &name, TfToken const &dataType,
218                         int level)
219                 : name(name), dataType(dataType), level(level) {}
220             TfToken name;
221             TfToken dataType;
222             int level;
223         };
224         typedef std::map<HdBinding, NestedPrimvar> NestedPrimvarBinding;
225 
226         // -------------------------------------------------------------------
227         // for shader parameter accessors
228         struct ShaderParameterAccessor {
ShaderParameterAccessorShaderParameterAccessor229              ShaderParameterAccessor() {}
230              ShaderParameterAccessor(TfToken const &name,
231                                      TfToken const &dataType,
232                                      std::string const &swizzle=std::string(),
233                                      TfTokenVector const &inPrimvars=TfTokenVector(),
234                                      bool const isPremultiplied=false,
235                                      bool const processTextureFallbackValue=false)
nameShaderParameterAccessor236                  : name(name), dataType(dataType), swizzle(swizzle),
237                   inPrimvars(inPrimvars), isPremultiplied(isPremultiplied),
238                   processTextureFallbackValue(processTextureFallbackValue) {}
239              TfToken name;        // e.g. Kd
240              TfToken dataType;    // e.g. vec4
241              std::string swizzle; // e.g. xyzw
242              TfTokenVector inPrimvars; // for primvar renaming and texture
243                                        // coordinates,
244              bool isPremultiplied; // indicates if texture parameter has been
245                                    // pre-multiplied by alpha on the CPU
246              bool processTextureFallbackValue; // use NAME_fallback from shader
247                                                // bar if texture is not valid
248                                                // (determineed from bool
249                                                // NAME_valid or bindless
250                                                // handle), only supported for
251                                                // material shader and for uv
252                                                // and field textures.
253         };
254         typedef std::map<HdBinding, ShaderParameterAccessor> ShaderParameterBinding;
255 
256         // -------------------------------------------------------------------
257         // for specific buffer array (drawing coordinate, instance indices)
258         struct BindingDeclaration {
BindingDeclarationBindingDeclaration259             BindingDeclaration() {}
BindingDeclarationBindingDeclaration260             BindingDeclaration(TfToken const &name,
261                          TfToken const &dataType,
262                          HdBinding binding)
263                 : name(name), dataType(dataType), binding(binding) {}
264             TfToken name;
265             TfToken dataType;
266             HdBinding binding;
267         };
268 
269         // -------------------------------------------------------------------
270 
271         StructBlockBinding constantData;
272         StructBlockBinding shaderData;
273         StructBlockBinding topologyVisibilityData;
274         PrimvarBinding elementData;
275         PrimvarBinding vertexData;
276         PrimvarBinding varyingData;
277         FvarPrimvarBinding fvarData;
278         PrimvarBinding computeReadWriteData;
279         PrimvarBinding computeReadOnlyData;
280         NestedPrimvarBinding instanceData;
281         int instancerNumLevels;
282 
283         ShaderParameterBinding shaderParameterBinding;
284 
285         BindingDeclaration drawingCoord0Binding;
286         BindingDeclaration drawingCoord1Binding;
287         BindingDeclaration drawingCoord2Binding;
288         BindingDeclaration drawingCoordIBinding;
289         BindingDeclaration instanceIndexArrayBinding;
290         BindingDeclaration culledInstanceIndexArrayBinding;
291         BindingDeclaration instanceIndexBaseBinding;
292         BindingDeclaration primitiveParamBinding;
293         BindingDeclaration edgeIndexBinding;
294         BindingDeclaration coarseFaceIndexBinding;
295         std::vector<BindingDeclaration> fvarPatchParamBindings;
296         std::vector<BindingDeclaration> fvarIndicesBindings;
297 
298         StructBlockBinding customInterleavedBindings;
299         std::vector<BindingDeclaration> customBindings;
300     };
301 
302     /// Constructor.
303     HDST_API
304     HdSt_ResourceBinder();
305 
306     /// Assign all binding points used in drawitem and custom bindings.
307     /// Returns metadata to be used for codegen.
308     HDST_API
309     void ResolveBindings(HdStDrawItem const *drawItem,
310                          HdStShaderCodeSharedPtrVector const &shaders,
311                          MetaData *metaDataOut,
312                          bool indirect,
313                          bool instanceDraw,
314                          HdBindingRequestVector const &customBindings);
315 
316     /// Assign all binding points used in computation.
317     /// Returns metadata to be used for codegen.
318     HDST_API
319     void ResolveComputeBindings(HdBufferSpecVector const &readWriteBufferSpecs,
320                                 HdBufferSpecVector const &readOnlyBufferSpecs,
321                                 HdStShaderCodeSharedPtrVector const &shaders,
322                                 MetaData *metaDataOut);
323 
324     /// call GL introspection APIs and fix up binding locations,
325     /// in case if explicit resource location qualifier is not available
326     /// (GL 4.2 or before)
327     HDST_API
328     void IntrospectBindings(HgiShaderProgramHandle const & hgiProgram);
329 
330     HDST_API
331     void Bind(HdBindingRequest const& req) const;
332     HDST_API
333     void Unbind(HdBindingRequest const& req) const;
334 
335     /// bind/unbind BufferArray
336     HDST_API
337     void BindBufferArray(HdStBufferArrayRangeSharedPtr const &bar) const;
338     HDST_API
339     void UnbindBufferArray(HdStBufferArrayRangeSharedPtr const &bar) const;
340 
341     /// bind/unbind interleaved constant buffer
342     HDST_API
343     void BindConstantBuffer(
344         HdStBufferArrayRangeSharedPtr const & constantBar) const;
345     HDST_API
346     void UnbindConstantBuffer(
347         HdStBufferArrayRangeSharedPtr const &constantBar) const;
348 
349     /// bind/unbind interleaved buffer
350     HDST_API
351     void BindInterleavedBuffer(
352         HdStBufferArrayRangeSharedPtr const & constantBar,
353         TfToken const &name) const;
354     HDST_API
355     void UnbindInterleavedBuffer(
356         HdStBufferArrayRangeSharedPtr const &constantBar,
357         TfToken const &name) const;
358 
359     /// bind/unbind nested instance BufferArray
360     HDST_API
361     void BindInstanceBufferArray(
362         HdStBufferArrayRangeSharedPtr const &bar, int level) const;
363     HDST_API
364     void UnbindInstanceBufferArray(
365         HdStBufferArrayRangeSharedPtr const &bar, int level) const;
366 
367     /// bind/unbind shader parameters and textures
368     HDST_API
369     void BindShaderResources(HdStShaderCode const *shader) const;
370     HDST_API
371     void UnbindShaderResources(HdStShaderCode const *shader) const;
372 
373     /// piecewise buffer binding utility
374     /// (to be used for frustum culling, draw indirect result)
375     HDST_API
376     void BindBuffer(TfToken const &name,
377                     HdStBufferResourceSharedPtr const &resource) const;
378     HDST_API
379     void BindBuffer(TfToken const &name,
380                     HdStBufferResourceSharedPtr const &resource,
381                     int offset, int level=-1) const;
382     HDST_API
383     void UnbindBuffer(TfToken const &name,
384                       HdStBufferResourceSharedPtr const &resource,
385                       int level=-1) const;
386 
387     /// bind(update) a standalone uniform (unsigned int)
388     HDST_API
389     void BindUniformui(TfToken const &name, int count,
390                        const unsigned int *value) const;
391 
392     /// bind a standalone uniform (signed int, ivec2, ivec3, ivec4)
393     HDST_API
394     void BindUniformi(TfToken const &name, int count, const int *value) const;
395 
396     /// bind a standalone uniform array (int[N])
397     HDST_API
398     void BindUniformArrayi(TfToken const &name, int count, const int *value) const;
399 
400     /// bind a standalone uniform (float, vec2, vec3, vec4, mat4)
401     HDST_API
402     void BindUniformf(TfToken const &name, int count, const float *value) const;
403 
404     /// Returns whether a binding exists.
405     bool HasBinding(TfToken const &name, int level=-1) const {
406         return _bindingMap.find(NameAndLevel(name, level)) != _bindingMap.end();
407     }
408 
409     /// Returns binding point.
410     /// XXX: exposed temporarily for drawIndirectResult
411     /// see Hd_IndirectDrawBatch::_BeginGPUCountVisibleInstances()
412     HdBinding GetBinding(TfToken const &name, int level=-1) const {
413         HdBinding binding;
414         TfMapLookup(_bindingMap, NameAndLevel(name, level), &binding);
415         return binding;
416     }
417 
GetNumReservedUniformBlockLocations()418     int GetNumReservedUniformBlockLocations() const {
419         return _numReservedUniformBlockLocations;
420     }
421 
GetNumReservedTextureUnits()422     int GetNumReservedTextureUnits() const {
423         return _numReservedTextureUnits;
424     }
425 
426     /// Returns \c true if textures and samplers for material
427     /// networks use bindless texture and sampler handles.
428     HDST_API
429     static bool UseBindlessHandles();
430 
431     /// Returns the bindless handle for \p textureHandle using \p samplerHandle
432     HDST_API
433     static uint64_t GetSamplerBindlessHandle(
434         HgiSamplerHandle const &samplerHandle,
435         HgiTextureHandle const &textureHandle);
436 
437     /// Returns the bindless handle for \p textureHandle w/o separate sampler
438     HDST_API
439     static uint64_t GetTextureBindlessHandle(
440         HgiTextureHandle const &textureHandle);
441 
442     /// Binds the sampler and texture for \p name
443     /// Does nothing if the named resource is a bindless resource.
444     HDST_API
445     void BindTexture(const TfToken &name,
446                      HgiSamplerHandle const &samplerHandle,
447                      HgiTextureHandle const &textureHandle,
448                      const bool bind) const;
449 
450     /// Binds the sampler and texture for \p name along with an additional
451     /// layout texture as needed for Ptex or UDIM textures.
452     /// Does nothing if the named resource is a bindless resource.
453     HDST_API
454     void BindTextureWithLayout(TfToken const &name,
455                                HgiSamplerHandle const &texelSampler,
456                                HgiTextureHandle const &texelTexture,
457                                HgiTextureHandle const &layoutTexture,
458                                const bool bind) const;
459 
460 private:
461     // for batch execution
462     struct NameAndLevel {
463         NameAndLevel(TfToken const &n, int lv=-1) :
nameNameAndLevel464             name(n), level(lv) {}
465         TfToken name;
466         int level;
467 
468         bool operator < (NameAndLevel const &other) const {
469             return name  < other.name ||
470                   (name == other.name && level < other.level);
471         }
472     };
473     typedef std::map<NameAndLevel, HdBinding> _BindingMap;
474     _BindingMap _bindingMap;
475     int _numReservedUniformBlockLocations;
476     int _numReservedTextureUnits;
477 };
478 
479 
480 PXR_NAMESPACE_CLOSE_SCOPE
481 
482 #endif  // PXR_IMAGING_HD_ST_RESOURCE_BINDER_H
483