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_BINDING_H
25 #define PXR_IMAGING_HD_BINDING_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/imaging/hd/api.h"
29 #include "pxr/imaging/hd/version.h"
30 #include "pxr/imaging/hd/types.h"
31 
32 #include "pxr/imaging/hd/bufferResource.h"
33 #include "pxr/imaging/hd/bufferArrayRange.h"
34 
35 #include "pxr/base/tf/hash.h"
36 
37 PXR_NAMESPACE_OPEN_SCOPE
38 
39 
40 typedef std::vector<class HdBinding> HdBindingVector;
41 typedef std::vector<class HdBindingRequest> HdBindingRequestVector;
42 
43 /// \class HdBinding
44 ///
45 /// Bindings are used for buffers or textures, it simple associates a binding
46 /// type with a binding location.
47 ///
48 class HdBinding {
49 public:
50     enum Type { // primvar, drawing coordinate and dispatch buffer bindings
51                 // also shader fallback values
52                 UNKNOWN,
53                 DISPATCH,            // GL_DRAW_INDIRECT_BUFFER
54                 DRAW_INDEX,          // per-drawcall. not instanced
55                 DRAW_INDEX_INSTANCE, // per-drawcall. attribdivisor=on
56                 DRAW_INDEX_INSTANCE_ARRAY, // per-drawcall. attribdivisor=on, array
57                 VERTEX_ATTR,         // vertex-attribute
58                 INDEX_ATTR,          // GL_ELEMENT_ARRAY_BUFFER
59                 SSBO,                //
60                 BINDLESS_SSBO_RANGE, //
61                 UBO,                 //
62                 BINDLESS_UNIFORM,    //
63                 UNIFORM,             //
64                 UNIFORM_ARRAY,       //
65 
66                 // shader parameter bindings
67                 FALLBACK,             // fallback value
68                 TEXTURE_2D,           // non-bindless uv texture
69                 TEXTURE_FIELD,        // non-bindless field texture
70                                       // creates accessor that samples uvw
71                                       // texture after transforming coordinates
72                                       // by a sampling transform
73                 TEXTURE_UDIM_ARRAY,   // non-bindless udim texture array
74                 TEXTURE_UDIM_LAYOUT,  // non-bindless udim layout
75                 TEXTURE_PTEX_TEXEL,   // non-bindless ptex texels
76                 TEXTURE_PTEX_LAYOUT,  // non-bindless ptex layout
77                 BINDLESS_TEXTURE_2D,          // bindless uv texture
78                 BINDLESS_TEXTURE_FIELD,       // bindless field texture
79                                               // (see above)
80                 BINDLESS_TEXTURE_UDIM_ARRAY,  // bindless uv texture array
81                 BINDLESS_TEXTURE_UDIM_LAYOUT, // bindless udim layout
82                 BINDLESS_TEXTURE_PTEX_TEXEL,  // bindless ptex texels
83                 BINDLESS_TEXTURE_PTEX_LAYOUT, // bindless ptex layout
84                 PRIMVAR_REDIRECT,    // primvar redirection
85                 FIELD_REDIRECT, // accesses a field texture by name and
86                                 // uses fallbackValue if no accessor for
87                                 // the texture exists.
88                 TRANSFORM_2D    // transform2d
89     };
90     enum Location {
91                 // NOT_EXIST is a special value of location for a uniform
92                 // which is assigned but optimized out after linking program.
93                 NOT_EXIST = 0xffff
94     };
HdBinding()95     HdBinding() : _typeAndLocation(-1) { }
96     HdBinding(Type type, int location, int textureUnit=0) {
97         Set(type, location, textureUnit);
98     }
Set(Type type,int location,int textureUnit)99     void Set(Type type, int location, int textureUnit) {
100         _typeAndLocation = (textureUnit << 24)|(location << 8)|(int)(type);
101     }
IsValid()102     bool IsValid() const { return _typeAndLocation >= 0; }
GetType()103     Type GetType() const { return (Type)(_typeAndLocation & 0xff); }
GetLocation()104     int GetLocation() const { return (_typeAndLocation >> 8) & 0xffff; }
GetTextureUnit()105     int GetTextureUnit() const { return (_typeAndLocation >> 24) & 0xff; }
GetValue()106     int GetValue() const { return _typeAndLocation; }
107     bool operator < (HdBinding const &b) const {
108         return (_typeAndLocation < b._typeAndLocation);
109     }
110 private:
111     int _typeAndLocation;
112 };
113 
114 /// BindingRequest allows externally allocated buffers to be bound at render
115 /// time. The different modes of binding discussed below allow the caller a
116 /// range of opt-in binding behaviors, from simply reserving a binding location
117 /// so it can be managed from client code, to fully generating buffer accessor
118 /// code at compile time (i.e. when using a BufferArrayRange or BufferResource).
119 ///
120 /// This is a "request" because the caller makes a request before bindings are
121 /// resolved. All requests are consulted and fulfilled during binding
122 /// resolution.
123 class HdBindingRequest {
124 public:
125 
126     HdBindingRequest() = default;
127 
128     /// A data binding, not backed by neither BufferArrayRange nor
129     /// BufferResource.  This binding request simply
130     /// generates named metadata (#define HD_HAS_foo 1, #define HD_foo_Binding)
HdBindingRequest(HdBinding::Type bindingType,TfToken const & name)131     HdBindingRequest(HdBinding::Type bindingType, TfToken const& name)
132         : _bindingType(bindingType)
133         , _dataType(HdTypeInvalid)
134         , _name(name)
135         , _resource(nullptr)
136         , _bar(nullptr)
137         , _isInterleaved(false)
138     {}
139 
140     /// A data binding, not backed by neither BufferArrayRange nor
141     /// BufferResource.
HdBindingRequest(HdBinding::Type bindingType,TfToken const & name,HdType dataType)142     HdBindingRequest(HdBinding::Type bindingType, TfToken const& name,
143                      HdType dataType)
144         : _bindingType(bindingType)
145         , _dataType(dataType)
146         , _name(name)
147         , _resource(nullptr)
148         , _bar(nullptr)
149         , _isInterleaved(false)
150     {}
151 
152     /// A buffer resource binding. Binds a given buffer resource to a specified
153     /// name.  The data type is set from the resource.
HdBindingRequest(HdBinding::Type bindingType,TfToken const & name,HdBufferResourceSharedPtr const & resource)154     HdBindingRequest(HdBinding::Type bindingType, TfToken const& name,
155                      HdBufferResourceSharedPtr const& resource)
156         : _bindingType(bindingType)
157         , _dataType(resource->GetTupleType().type)
158         , _name(name)
159         , _resource(resource)
160         , _bar(nullptr)
161         , _isInterleaved(false)
162     {}
163 
164     /// A named struct binding. From an interleaved BufferArray, an array of
165     /// structs will be generated, consuming a single binding point. Note that
166     /// all resources in the buffer array must have the same underlying
167     /// identifier, hence must be interleaved and bindable as a single resource.
168     /// Data types can be derived from each HdBufferResource of bar.
HdBindingRequest(HdBinding::Type type,TfToken const & name,HdBufferArrayRangeSharedPtr bar,bool interleave)169     HdBindingRequest(HdBinding::Type type, TfToken const& name,
170                     HdBufferArrayRangeSharedPtr bar,
171                     bool interleave)
172         : _bindingType(type)
173         , _dataType(HdTypeInvalid)
174         , _name(name)
175         , _resource(nullptr)
176         , _bar(bar)
177         , _isInterleaved(interleave)
178     {}
179 
180     // ---------------------------------------------------------------------- //
181     /// \name Discriminators
182     // ---------------------------------------------------------------------- //
183 
184     /// Resource bingings have a single associated Hydra resource, but no buffer
185     /// array.
IsResource()186     bool IsResource() const {
187         return bool(_resource);
188     }
189 
190     /// A buffer array binding has several buffers bundled together and each
191     /// buffer will be bound individually and exposed as independent arrays in
192     /// the shader.
IsBufferArray()193     bool IsBufferArray() const {
194         return _bar && !_isInterleaved;
195     }
196 
197     /// Like BufferArray binding requests, struct bindings have several buffers,
198     /// however they must be allocated into a single resource and interleaved.
199     /// This type of binding request is exposed in the shader an array of
200     ///  structs.
IsInterleavedBufferArray()201     bool IsInterleavedBufferArray() const {
202         return _bar && _isInterleaved;
203     }
204 
205     /// This binding is typelss. CodeGen only allocate location and
206     /// skip emitting declarations and accessors.
IsTypeless()207     bool IsTypeless() const {
208         return (!_bar) && (!_resource) && (_dataType == HdTypeInvalid);
209     }
210 
211     // ---------------------------------------------------------------------- //
212     /// \name Accessors
213     // ---------------------------------------------------------------------- //
214 
215     /// Returns the name of the binding point, if any; buffer arrays and structs
216     /// need not be named.
GetName()217     TfToken const& GetName() const {
218         return _name;
219     }
220     /// Returns the HdBinding type of this request.
GetBindingType()221     HdBinding::Type GetBindingType() const {
222         return _bindingType;
223     }
224     /// Returns the single resource associated with this binding request or
225     /// null when IsResource() returns false.
GetResource()226     HdBufferResourceSharedPtr const& GetResource() const {
227         return _resource;
228     }
229     /// Returns the resource or buffer array range offset, defaults to zero.
GetByteOffset()230     int GetByteOffset() const {
231         // buffer resource binding
232         if (_resource) return _resource->GetOffset();
233 
234         // named struct binding (interleaved) - the resource name doesn't matter
235         // since a single binding point is used.
236         if (_bar) return _bar->GetByteOffset(TfToken());
237         return 0;
238     }
239     /// Returns the buffer array range associated with this binding request or
240     /// null when IsBufferArrqay() returns false.
GetBar()241     HdBufferArrayRangeSharedPtr const& GetBar() const {
242         return _bar;
243     }
244 
245     /// Return the data type of this request
GetDataType()246     HdType GetDataType() const {
247         return _dataType;
248     }
249 
250     // ---------------------------------------------------------------------- //
251     /// \name Comparison
252     // ---------------------------------------------------------------------- //
253     HD_API
254     bool operator==(HdBindingRequest const &other) const;
255 
256     HD_API
257     bool operator!=(HdBindingRequest const &other) const;
258 
259     // ---------------------------------------------------------------------- //
260     /// \name Hash
261     // ---------------------------------------------------------------------- //
262 
263     /// Returns the hash corresponding to this buffer request.
264     ///
265     /// Note that this hash captures the structural state of the request, not
266     /// the contents. For example, buffer array versions/reallocations will not
267     /// affect hash, but changing the BAR pointer will.
268     HD_API
269     size_t ComputeHash() const;
270 
271     // TfHash support.
272     template <class HashState>
TfHashAppend(HashState & h,HdBindingRequest const & br)273     friend void TfHashAppend(HashState &h, HdBindingRequest const &br) {
274         h.Append(br._name,
275                  br._bindingType,
276                  br._dataType,
277                  br._isInterleaved);
278     }
279 
280 private:
281     // This class unfortunately represents several concepts packed into a single
282     // class.  Ideally, we would break this out as one class per concept,
283     // however that would also require virtual dispatch, which is overkill for
284     // the current use cases.
285 
286     // Named binding request
287     HdBinding::Type _bindingType;
288     HdType _dataType;
289     TfToken _name;
290 
291     // Resource binding request
292     HdBufferResourceSharedPtr _resource;
293 
294     // Struct binding request
295     HdBufferArrayRangeSharedPtr _bar;
296     bool _isInterleaved;
297 
298 };
299 
300 
301 PXR_NAMESPACE_CLOSE_SCOPE
302 
303 #endif  // PXR_IMAGING_HD_BINDING_H
304