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 #include "pxr/imaging/garch/glApi.h"
25 
26 #include "pxr/imaging/glf/contextCaps.h"
27 
28 #include "pxr/imaging/hdSt/resourceBinder.h"
29 #include "pxr/imaging/hdSt/glConversions.h"
30 #include "pxr/imaging/hdSt/bufferArrayRange.h"
31 #include "pxr/imaging/hdSt/bufferResource.h"
32 #include "pxr/imaging/hdSt/shaderCode.h"
33 #include "pxr/imaging/hdSt/drawItem.h"
34 #include "pxr/imaging/hdSt/materialNetworkShader.h"
35 #include "pxr/imaging/hdSt/materialParam.h"
36 #include "pxr/imaging/hdSt/textureBinder.h"
37 #include "pxr/imaging/hdSt/tokens.h"
38 #include "pxr/imaging/hd/bufferSpec.h"
39 #include "pxr/imaging/hd/enums.h"
40 #include "pxr/imaging/hd/instancer.h"
41 #include "pxr/imaging/hd/tokens.h"
42 
43 #include "pxr/imaging/hgiGL/buffer.h"
44 #include "pxr/imaging/hgiGL/texture.h"
45 #include "pxr/imaging/hgiGL/sampler.h"
46 #include "pxr/imaging/hgiGL/shaderProgram.h"
47 
48 #include "pxr/base/tf/staticTokens.h"
49 
50 #include <boost/functional/hash.hpp>
51 
52 PXR_NAMESPACE_OPEN_SCOPE
53 
54 TF_DEFINE_PUBLIC_TOKENS(HdSt_ResourceBindingSuffixTokens,
55                         HDST_RESOURCE_BINDING_SUFFIX_TOKENS);
56 
57 TF_DEFINE_PRIVATE_TOKENS(
58     _tokens,
59     ((_double, "double"))
60     ((_float, "float"))
61     ((_int, "int"))
62     (vec2)
63     (vec3)
64     (vec4)
65     (dvec2)
66     (dvec3)
67     (dvec4)
68     (ivec2)
69     (ivec3)
70     (ivec4)
71     (constantPrimvars)
72     (primitiveParam)
73     (topologyVisibility)
74 );
75 
76 namespace {
77     struct BindingLocator {
BindingLocator__anonb3ee4bde0111::BindingLocator78         BindingLocator() :
79             uniformLocation(0), uboLocation(0),
80             ssboLocation(0), attribLocation(0),
81             textureUnit(0) {}
82 
GetBinding__anonb3ee4bde0111::BindingLocator83         HdBinding GetBinding(HdBinding::Type type, TfToken const &debugName) {
84             switch(type) {
85             case HdBinding::UNIFORM:
86                 return HdBinding(HdBinding::UNIFORM, uniformLocation++);
87                 break;
88             case HdBinding::UBO:
89                 return HdBinding(HdBinding::UBO, uboLocation++);
90                 break;
91             case HdBinding::SSBO:
92                 return HdBinding(HdBinding::SSBO, ssboLocation++);
93                 break;
94             case HdBinding::BINDLESS_SSBO_RANGE:
95                 return HdBinding(HdBinding::BINDLESS_SSBO_RANGE, uniformLocation++);
96             case HdBinding::BINDLESS_UNIFORM:
97                 return HdBinding(HdBinding::BINDLESS_UNIFORM, uniformLocation++);
98                 break;
99             case HdBinding::VERTEX_ATTR:
100                 return HdBinding(HdBinding::VERTEX_ATTR, attribLocation++);
101                 break;
102             case HdBinding::DRAW_INDEX:
103                 return HdBinding(HdBinding::DRAW_INDEX, attribLocation++);
104                 break;
105             case HdBinding::DRAW_INDEX_INSTANCE:
106                 return HdBinding(HdBinding::DRAW_INDEX_INSTANCE, attribLocation++);
107                 break;
108             default:
109                 TF_CODING_ERROR("Unknown binding type %d for %s",
110                                 type, debugName.GetText());
111                 return HdBinding();
112                 break;
113             }
114         }
115 
116         int uniformLocation;
117         int uboLocation;
118         int ssboLocation;
119         int attribLocation;
120         int textureUnit;
121     };
122 
_ShouldBeNormalized(HdType type)123     static inline GLboolean _ShouldBeNormalized(HdType type) {
124         return type == HdTypeInt32_2_10_10_10_REV;
125     }
126 
127     // GL has special handling for the "number of components" for
128     // packed vectors.  Handle that here.
_GetNumComponents(HdType type)129     static inline int _GetNumComponents(HdType type) {
130         if (type == HdTypeInt32_2_10_10_10_REV) {
131             return 4;
132         } else {
133             return HdGetComponentCount(type);
134         }
135     }
136 
137     // Modify datatype if swizzle is specified
_AdjustHdType(HdType type,std::string const & swizzle)138     static HdType _AdjustHdType(HdType type, std::string const &swizzle) {
139         size_t numChannels = swizzle.size();
140         if (numChannels == 4) {
141             return HdTypeFloatVec4;
142         } else if (numChannels == 3) {
143             return HdTypeFloatVec3;
144         } else if (numChannels == 2) {
145             return HdTypeFloatVec2;
146         } else if (numChannels == 1) {
147             return HdTypeFloat;
148         }
149 
150         return type;
151     }
152 }
153 
HdSt_ResourceBinder()154 HdSt_ResourceBinder::HdSt_ResourceBinder()
155     : _numReservedUniformBlockLocations(0)
156     , _numReservedTextureUnits(0)
157 {
158 }
159 
160 static
161 TfToken
_ConcatLayout(const TfToken & token)162 _ConcatLayout(const TfToken &token)
163 {
164     return TfToken(
165         token.GetString()
166         + HdSt_ResourceBindingSuffixTokens->layout.GetString());
167 }
168 
169 static
170 TfTokenVector
_GetInstancerFilterNames(HdStDrawItem const * drawItem)171 _GetInstancerFilterNames(HdStDrawItem const * drawItem)
172 {
173     TfTokenVector filterNames = HdInstancer::GetBuiltinPrimvarNames();;
174 
175     HdSt_MaterialNetworkShaderSharedPtr materialNetworkShader =
176         drawItem->GetMaterialNetworkShader();
177     if (materialNetworkShader) {
178         TfTokenVector const & names = materialNetworkShader->GetPrimvarNames();
179         filterNames.insert(filterNames.end(), names.begin(), names.end());
180     }
181 
182     return filterNames;
183 }
184 
185 static
186 bool
_TokenContainsString(const TfToken & token,const std::string & string)187 _TokenContainsString(const TfToken &token, const std::string &string)
188 {
189     return (token.GetString().find(string) != std::string::npos);
190 }
191 
192 void
ResolveBindings(HdStDrawItem const * drawItem,HdStShaderCodeSharedPtrVector const & shaders,HdSt_ResourceBinder::MetaData * metaDataOut,bool indirect,bool instanceDraw,HdBindingRequestVector const & customBindings)193 HdSt_ResourceBinder::ResolveBindings(HdStDrawItem const *drawItem,
194                                    HdStShaderCodeSharedPtrVector const &shaders,
195                                    HdSt_ResourceBinder::MetaData *metaDataOut,
196                                    bool indirect,
197                                    bool instanceDraw,
198                                    HdBindingRequestVector const &customBindings)
199 {
200     HD_TRACE_FUNCTION();
201     HF_MALLOC_TAG_FUNCTION();
202 
203     if (!TF_VERIFY(metaDataOut)) return;
204 
205     // GL context caps
206     const bool ssboEnabled
207         = GlfContextCaps::GetInstance().shaderStorageBufferEnabled;
208     const bool bindlessUniformEnabled
209         = GlfContextCaps::GetInstance().bindlessBufferEnabled;
210     const bool bindlessTextureEnabled
211         = GlfContextCaps::GetInstance().bindlessTextureEnabled;
212 
213     HdBinding::Type arrayBufferBindingType = HdBinding::SSBO;
214     if (bindlessUniformEnabled) {
215         arrayBufferBindingType = HdBinding::BINDLESS_UNIFORM; // EXT
216     }
217 
218     HdBinding::Type structBufferBindingType = HdBinding::UBO;  // 3.1
219     if (bindlessUniformEnabled) {
220         structBufferBindingType = HdBinding::BINDLESS_UNIFORM; // EXT
221     } else if (ssboEnabled) {
222         structBufferBindingType = HdBinding::SSBO;             // 4.3
223     }
224 
225     HdBinding::Type drawingCoordBindingType = HdBinding::UNIFORM;
226     if (indirect) {
227         if (instanceDraw) {
228             drawingCoordBindingType = HdBinding::DRAW_INDEX_INSTANCE;
229         } else {
230             drawingCoordBindingType = HdBinding::DRAW_INDEX;
231         }
232     }
233 
234     // binding assignments
235     BindingLocator locator;
236 
237     int bindlessTextureLocation = 0;
238     // Note that these locations are used for hash keys only and
239     // are never used for actual resource binding.
240     int shaderFallbackLocation = 0;
241     int shaderPrimvarRedirectLocation = 0;
242     int shaderFieldRedirectLocation = 0;
243     int shaderTransform2dLocation = 0;
244 
245     // clear all
246     _bindingMap.clear();
247 
248     // constant primvar (per-object)
249     HdBinding constantPrimvarBinding =
250                 locator.GetBinding(structBufferBindingType,
251                                    _tokens->constantPrimvars);
252 
253     if (HdBufferArrayRangeSharedPtr constantBar_ =
254         drawItem->GetConstantPrimvarRange()) {
255 
256         HdStBufferArrayRangeSharedPtr constantBar =
257             std::static_pointer_cast<HdStBufferArrayRange>(constantBar_);
258 
259         MetaData::StructBlock sblock(_tokens->constantPrimvars);
260         TF_FOR_ALL (it, constantBar->GetResources()) {
261             HdTupleType valueType = it->second->GetTupleType();
262             TfToken glType = HdStGLConversions::GetGLSLTypename(valueType.type);
263             TfToken glName =  HdStGLConversions::GetGLSLIdentifier(it->first);
264             sblock.entries.emplace_back(
265                 /*name=*/glName,
266                 /*type=*/glType,
267                 /*offset=*/it->second->GetOffset(),
268                 /*arraySize=*/valueType.count);
269         }
270         // sort by offset
271         // XXX: not robust enough, should consider padding and layouting rules
272         // to match with the logic in HdInterleavedMemoryManager if we
273         // want to use a layouting policy other than default padding.
274         std::sort(sblock.entries.begin(), sblock.entries.end());
275 
276         metaDataOut->constantData.insert(
277             std::make_pair(constantPrimvarBinding, sblock));
278     }
279 
280      // constant primvars are interleaved into single struct.
281     _bindingMap[_tokens->constantPrimvars] = constantPrimvarBinding;
282 
283     TfTokenVector filterNames = _GetInstancerFilterNames(drawItem);
284 
285     // instance primvar (per-instance)
286     int instancerNumLevels = drawItem->GetInstancePrimvarNumLevels();
287     metaDataOut->instancerNumLevels = instancerNumLevels;
288     for (int i = 0; i < instancerNumLevels; ++i) {
289         if (HdBufferArrayRangeSharedPtr instanceBar_ =
290             drawItem->GetInstancePrimvarRange(i)) {
291 
292             HdStBufferArrayRangeSharedPtr instanceBar =
293                 std::static_pointer_cast<HdStBufferArrayRange>(instanceBar_);
294 
295             TF_FOR_ALL (it, instanceBar->GetResources()) {
296                 TfToken const& name = it->first;
297                 // skip instance primvars that are not used in this batch.
298                 if (std::find(filterNames.begin(), filterNames.end(), name)
299                                                         == filterNames.end()) {
300                     continue;
301                 }
302 
303                 TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
304                 // non-interleaved, always create new binding.
305                 HdBinding instancePrimvarBinding =
306                     locator.GetBinding(arrayBufferBindingType, name);
307                 _bindingMap[NameAndLevel(name, i)] = instancePrimvarBinding;
308 
309                 HdTupleType valueType = it->second->GetTupleType();
310                 TfToken glType =
311                     HdStGLConversions::GetGLSLTypename(valueType.type);
312                 metaDataOut->instanceData[instancePrimvarBinding] =
313                     MetaData::NestedPrimvar(
314                         /*name=*/glName,
315                         /*type=*/glType,
316                         /*level=*/i);
317             }
318         }
319     }
320 
321     // vertex primvar (per-vertex)
322     // always assigned to VertexAttribute.
323     if (HdBufferArrayRangeSharedPtr vertexBar_ =
324         drawItem->GetVertexPrimvarRange()) {
325 
326         HdStBufferArrayRangeSharedPtr vertexBar =
327             std::static_pointer_cast<HdStBufferArrayRange>(vertexBar_);
328 
329         TF_FOR_ALL (it, vertexBar->GetResources()) {
330             TfToken const& name = it->first;
331             TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
332             HdBinding vertexPrimvarBinding =
333                 locator.GetBinding(HdBinding::VERTEX_ATTR, name);
334             _bindingMap[name] = vertexPrimvarBinding;
335 
336             HdTupleType valueType = it->second->GetTupleType();
337             // Special case: VBOs have intrinsic support for packed types,
338             // so expand them out to their target type for the shader binding.
339             if (valueType.type == HdTypeInt32_2_10_10_10_REV) {
340                 valueType.type = HdTypeFloatVec4;
341             } else if (valueType.type == HdTypeHalfFloatVec2) {
342                 valueType.type = HdTypeFloatVec2;
343             } else if (valueType.type == HdTypeHalfFloatVec4) {
344                 valueType.type = HdTypeFloatVec4;
345             }
346             TfToken glType = HdStGLConversions::GetGLSLTypename(valueType.type);
347             metaDataOut->vertexData[vertexPrimvarBinding] =
348                 MetaData::Primvar(/*name=*/glName,
349                                   /*type=*/glType);
350         }
351     }
352 
353     // varying primvar
354     if (HdBufferArrayRangeSharedPtr varyingBar_ =
355         drawItem->GetVaryingPrimvarRange()) {
356 
357         HdStBufferArrayRangeSharedPtr varyingBar =
358             std::static_pointer_cast<HdStBufferArrayRange>(varyingBar_);
359 
360         for (const auto &resource : varyingBar->GetResources()) {
361             TfToken const& name = resource.first;
362             TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
363             HdBinding varyingPrimvarBinding =
364                 locator.GetBinding(arrayBufferBindingType, name);
365             _bindingMap[name] = varyingPrimvarBinding;
366 
367             HdTupleType valueType = resource.second->GetTupleType();
368             TfToken glType = HdStGLConversions::GetGLSLTypename(valueType.type);
369             metaDataOut->varyingData[varyingPrimvarBinding] =
370                 MetaData::Primvar(/*name=*/glName,
371                                   /*type=*/glType);
372         }
373     }
374 
375     // index buffer
376     if (HdBufferArrayRangeSharedPtr topologyBar_ =
377         drawItem->GetTopologyRange()) {
378 
379         HdStBufferArrayRangeSharedPtr topologyBar =
380             std::static_pointer_cast<HdStBufferArrayRange>(topologyBar_);
381 
382         TF_FOR_ALL (it, topologyBar->GetResources()) {
383             // Don't need to sanitize the name, since topology resources are
384             // created internally.
385             TfToken const& name = it->first;
386             HdStBufferResourceSharedPtr const& resource = it->second;
387 
388             if (name == HdTokens->indices) {
389                 // IBO. no need for codegen
390                 _bindingMap[name] = HdBinding(HdBinding::INDEX_ATTR, 0);
391             } else {
392                 // We expect the following additional topology based info:
393                 // - primitive parameter (for all tris, quads and patches)
394                 // - edge indices (for all tris, quads and patches)
395                 // - fvar indices (for refined tris, quads, and patches with
396                 //   face-varying primvars)
397                 // - fvar patch params (for refined tris, quads, and patches
398                 //   with face-varying primvars)
399 
400                 HdBinding binding =
401                     locator.GetBinding(arrayBufferBindingType, name);
402                 _bindingMap[name] = binding;
403 
404                 HdTupleType valueType = resource->GetTupleType();
405                 TfToken glType =
406                     HdStGLConversions::GetGLSLTypename(valueType.type);
407 
408                 auto bindingDecl = MetaData::BindingDeclaration(
409                                      /*name=*/name,
410                                      /*type=*/glType,
411                                      /*binding=*/binding);
412 
413                 if (name == HdTokens->primitiveParam) {
414                     metaDataOut->primitiveParamBinding = bindingDecl;
415                 } else if (name == HdTokens->edgeIndices) {
416                     metaDataOut->edgeIndexBinding = bindingDecl;
417                 } else if (name == HdStTokens->coarseFaceIndex) {
418                     metaDataOut->coarseFaceIndexBinding = bindingDecl;
419                 } else if (_TokenContainsString(name,
420                            HdStTokens->fvarIndices.GetString())) {
421                     metaDataOut->fvarIndicesBindings.push_back(bindingDecl);
422                 } else if (_TokenContainsString(name,
423                            HdStTokens->fvarPatchParam.GetString())) {
424                     metaDataOut->fvarPatchParamBindings.push_back(bindingDecl);
425                 } else {
426                     TF_WARN("Unexpected topological resource '%s'\n",
427                     name.GetText());
428                 }
429             }
430         }
431     }
432 
433      // topology visibility
434     HdBinding topologyVisibilityBinding =
435                 locator.GetBinding(structBufferBindingType,
436                                    /*debugName*/_tokens->topologyVisibility);
437 
438     if (HdBufferArrayRangeSharedPtr topVisBar_ =
439         drawItem->GetTopologyVisibilityRange()) {
440 
441         HdStBufferArrayRangeSharedPtr topVisBar =
442             std::static_pointer_cast<HdStBufferArrayRange>(topVisBar_);
443 
444         MetaData::StructBlock sblock(_tokens->topologyVisibility);
445         TF_FOR_ALL (it, topVisBar->GetResources()) {
446             HdTupleType valueType = it->second->GetTupleType();
447             TfToken glType = HdStGLConversions::GetGLSLTypename(valueType.type);
448             sblock.entries.emplace_back(
449                 /*name=*/it->first,
450                 /*type=*/glType,
451                 /*offset=*/it->second->GetOffset(),
452                 /*arraySize=*/valueType.count);
453         }
454 
455         std::sort(sblock.entries.begin(), sblock.entries.end());
456 
457         metaDataOut->topologyVisibilityData.insert(
458             std::make_pair(topologyVisibilityBinding, sblock));
459     }
460 
461      // topology visibility is interleaved into single struct.
462     _bindingMap[_tokens->topologyVisibility] = topologyVisibilityBinding;
463 
464     // element primvar (per-face, per-line)
465     if (HdBufferArrayRangeSharedPtr elementBar_ =
466         drawItem->GetElementPrimvarRange()) {
467 
468         HdStBufferArrayRangeSharedPtr elementBar =
469             std::static_pointer_cast<HdStBufferArrayRange>(elementBar_);
470 
471         TF_FOR_ALL (it, elementBar->GetResources()) {
472             TfToken const& name = it->first;
473             TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
474             HdBinding elementPrimvarBinding =
475                 locator.GetBinding(arrayBufferBindingType, name);
476             _bindingMap[name] = elementPrimvarBinding;
477             HdTupleType valueType = it->second->GetTupleType();
478                 TfToken glType =
479                     HdStGLConversions::GetGLSLTypename(valueType.type);
480             metaDataOut->elementData[elementPrimvarBinding] =
481                 MetaData::Primvar(/*name=*/glName,
482                                   /*type=*/glType);
483         }
484     }
485 
486     // facevarying primvar (per-face-vertex)
487     if (HdBufferArrayRangeSharedPtr fvarBar_ =
488         drawItem->GetFaceVaryingPrimvarRange()) {
489 
490         HdStBufferArrayRangeSharedPtr fvarBar =
491             std::static_pointer_cast<HdStBufferArrayRange>(fvarBar_);
492 
493         TopologyToPrimvarVector const & fvarTopoToPvMap =
494             drawItem->GetFvarTopologyToPrimvarVector();
495 
496         TF_FOR_ALL (it, fvarBar->GetResources()) {
497             TfToken const& name = it->first;
498             TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
499 
500             HdBinding fvarPrimvarBinding =
501                 locator.GetBinding(arrayBufferBindingType, name);
502             _bindingMap[name] = fvarPrimvarBinding;
503             HdTupleType valueType = it->second->GetTupleType();
504             TfToken glType = HdStGLConversions::GetGLSLTypename(valueType.type);
505 
506             // Fine if no channel is found, might be unrefined primvar
507             int fvarChannel = 0;
508             for (size_t i = 0; i < fvarTopoToPvMap.size(); ++i) {
509                 if (std::find(fvarTopoToPvMap[i].second.begin(),
510                               fvarTopoToPvMap[i].second.end(),
511                               name) != fvarTopoToPvMap[i].second.end()) {
512                     fvarChannel = i;
513                 }
514             }
515 
516             metaDataOut->fvarData[fvarPrimvarBinding] =
517                 MetaData::FvarPrimvar(/*name=*/glName,
518                                       /*type=*/glType,
519                                       /*channel=*/fvarChannel);
520         }
521     }
522 
523     // draw parameter
524     // assigned to draw index (vertex attributeI w/divisor) (indiect)
525     // assigned to uniform          (immediate)
526     //
527     // note that instanceDraw may be true even for non-instance drawing,
528     // because there's only instanced version of glMultiDrawElementsIndirect.
529     HdBinding drawingCoord0Binding = locator.GetBinding(
530         drawingCoordBindingType, HdTokens->drawingCoord0);
531     _bindingMap[HdTokens->drawingCoord0] = drawingCoord0Binding;
532     metaDataOut->drawingCoord0Binding =
533         MetaData::BindingDeclaration(/*name=*/HdTokens->drawingCoord0,
534                                      /*type=*/_tokens->ivec4,
535                                      /*binding=*/drawingCoord0Binding);
536 
537     HdBinding drawingCoord1Binding = locator.GetBinding(
538         drawingCoordBindingType, HdTokens->drawingCoord1);
539     _bindingMap[HdTokens->drawingCoord1] = drawingCoord1Binding;
540     metaDataOut->drawingCoord1Binding =
541         MetaData::BindingDeclaration(/*name=*/HdTokens->drawingCoord1,
542                                      /*type=*/_tokens->ivec4,
543                                      /*binding=*/drawingCoord1Binding);
544 
545     HdBinding drawingCoord2Binding = locator.GetBinding(
546         drawingCoordBindingType, HdTokens->drawingCoord2);
547     _bindingMap[HdTokens->drawingCoord2] = drawingCoord2Binding;
548     metaDataOut->drawingCoord2Binding =
549         MetaData::BindingDeclaration(/*name=*/HdTokens->drawingCoord2,
550                                      /*type=*/_tokens->ivec2,
551                                      /*binding=*/drawingCoord2Binding);
552 
553     if (instancerNumLevels > 0) {
554         HdBinding drawingCoordIBinding = indirect
555             ? HdBinding(HdBinding::DRAW_INDEX_INSTANCE_ARRAY, locator.attribLocation)
556             : HdBinding(HdBinding::UNIFORM_ARRAY, locator.uniformLocation);
557         if (indirect) {
558             // each vertex attribute takes 1 location
559             locator.attribLocation += instancerNumLevels;
560         } else {
561             // int[N] may consume more than 1 location
562             locator.uniformLocation += instancerNumLevels;
563         }
564         _bindingMap[HdTokens->drawingCoordI] = drawingCoordIBinding;
565         metaDataOut->drawingCoordIBinding =
566             MetaData::BindingDeclaration(/*name=*/HdTokens->drawingCoordI,
567                                          /*type=*/_tokens->_int,
568                                          /*binding=*/drawingCoordIBinding);
569     }
570 
571     // instance index indirection buffer
572     if (HdBufferArrayRangeSharedPtr instanceIndexBar_ =
573         drawItem->GetInstanceIndexRange()) {
574 
575         HdStBufferArrayRangeSharedPtr instanceIndexBar =
576             std::static_pointer_cast<HdStBufferArrayRange>(
577                                                         instanceIndexBar_);
578 
579         HdStBufferResourceSharedPtr instanceIndices
580             = instanceIndexBar->GetResource(
581                                     HdInstancerTokens->instanceIndices);
582         HdStBufferResourceSharedPtr culledInstanceIndices
583             = instanceIndexBar->GetResource(
584                                     HdInstancerTokens->culledInstanceIndices);
585 
586         if (instanceIndices) {
587             HdBinding instanceIndexArrayBinding =
588                 locator.GetBinding(arrayBufferBindingType,
589                                    HdInstancerTokens->instanceIndices);
590             _bindingMap[HdInstancerTokens->instanceIndices] =
591                 instanceIndexArrayBinding;
592             HdTupleType valueType = instanceIndices->GetTupleType();
593                 TfToken glType =
594                     HdStGLConversions::GetGLSLTypename(valueType.type);
595             metaDataOut->instanceIndexArrayBinding =
596                 MetaData::BindingDeclaration(
597                     /*name=*/HdInstancerTokens->instanceIndices,
598                     /*type=*/glType,
599                     /*binding=*/instanceIndexArrayBinding);
600         }
601         if (culledInstanceIndices) {
602             HdBinding culledInstanceIndexArrayBinding =
603                 locator.GetBinding(arrayBufferBindingType,
604                                    HdInstancerTokens->culledInstanceIndices);
605             _bindingMap[HdInstancerTokens->culledInstanceIndices] =
606                 culledInstanceIndexArrayBinding;
607             HdTupleType valueType = instanceIndices->GetTupleType();
608                 TfToken glType =
609                     HdStGLConversions::GetGLSLTypename(valueType.type);
610             metaDataOut->culledInstanceIndexArrayBinding =
611                 MetaData::BindingDeclaration(
612                     /*name=*/HdInstancerTokens->culledInstanceIndices,
613                     /*type=*/glType,
614                     /*binding=*/culledInstanceIndexArrayBinding);
615         }
616     }
617 
618     // indirect dispatch
619     if (indirect) {
620         HdBinding dispatchBinding(HdBinding::DISPATCH, /*location=(not used)*/0);
621         _bindingMap[HdTokens->drawDispatch] = dispatchBinding;
622     }
623 
624     // shader parameter bindings
625     TF_FOR_ALL(shader, shaders) {
626 
627         // uniform block
628         HdBufferArrayRangeSharedPtr const &shaderBar_ =
629                                                 (*shader)->GetShaderData();
630         HdStBufferArrayRangeSharedPtr shaderBar =
631             std::static_pointer_cast<HdStBufferArrayRange> (shaderBar_);
632         if (shaderBar) {
633             HdBinding shaderParamBinding =
634                 locator.GetBinding(structBufferBindingType,
635                                     HdTokens->materialParams);
636 
637             // for fallback values and bindless textures
638             // XXX: name of sblock must be unique for each shaders.
639             MetaData::StructBlock sblock(HdTokens->materialParams);
640             TF_FOR_ALL(it, shaderBar->GetResources()) {
641                 TfToken const& name = it->first;
642                 TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
643                 HdTupleType valueType = it->second->GetTupleType();
644                 TfToken glType =
645                     HdStGLConversions::GetGLSLTypename(valueType.type);
646                 sblock.entries.emplace_back(
647                     /*name=*/glName,
648                     /*type=*/glType,
649                     /*offset=*/it->second->GetOffset(),
650                     /*arraySize=*/valueType.count);
651             }
652             // sort by offset
653             std::sort(sblock.entries.begin(), sblock.entries.end());
654             metaDataOut->shaderData.insert(
655                 std::make_pair(shaderParamBinding, sblock));
656 
657             //XXX:hack  we want to generalize materialParams to other shaders.
658             if ((*shader) == drawItem->GetMaterialNetworkShader()) {
659                 // shader parameters are interleaved into single struct.
660                 _bindingMap[HdTokens->materialParams] = shaderParamBinding;
661             }
662         }
663 
664         HdSt_MaterialParamVector params = (*shader)->GetParams();
665         // for primvar and texture accessors
666         for (HdSt_MaterialParam const& param : params) {
667             const bool isMaterialShader =
668                 ((*shader) == drawItem->GetMaterialNetworkShader());
669 
670             // renderpass texture should be bindfull (for now)
671             const bool bindless = bindlessTextureEnabled && isMaterialShader;
672             std::string const& glSwizzle = param.swizzle;
673             HdTupleType valueType = param.GetTupleType();
674             TfToken glType =
675                 HdStGLConversions::GetGLSLTypename(_AdjustHdType(valueType.type,
676                                                                  glSwizzle));
677             TfToken const& name = param.name;
678             TfToken glName =  HdStGLConversions::GetGLSLIdentifier(name);
679 
680             if (param.IsFallback()) {
681                 metaDataOut->shaderParameterBinding[
682                             HdBinding(HdBinding::FALLBACK,
683                             shaderFallbackLocation++)]
684                     = MetaData::ShaderParameterAccessor(glName,
685                                                         /*type=*/glType);
686             }
687             else if (param.IsTexture()) {
688                 if (param.textureType == HdTextureType::Ptex) {
689                     // ptex texture
690                     HdBinding texelBinding = bindless
691                         ? HdBinding(HdBinding::BINDLESS_TEXTURE_PTEX_TEXEL,
692                                     bindlessTextureLocation++)
693                         : HdBinding(HdBinding::TEXTURE_PTEX_TEXEL,
694                                     locator.uniformLocation++,
695                                     locator.textureUnit++);
696 
697                     metaDataOut->shaderParameterBinding[texelBinding] =
698                         MetaData::ShaderParameterAccessor(
699                             /*name=*/glName,
700                             /*type=*/glType,
701                             /*swizzle=*/glSwizzle,
702                             /*inPrimvars=*/param.samplerCoords,
703                             /*isPremultiplied=*/param.isPremultiplied);
704                     _bindingMap[name] = texelBinding; // used for non-bindless
705 
706                     HdBinding layoutBinding = bindless
707                         ? HdBinding(HdBinding::BINDLESS_TEXTURE_PTEX_LAYOUT,
708                                     bindlessTextureLocation++)
709                         : HdBinding(HdBinding::TEXTURE_PTEX_LAYOUT,
710                                     locator.uniformLocation++,
711                                     locator.textureUnit++);
712 
713                     const TfToken glLayoutName(_ConcatLayout(glName));
714                     metaDataOut->shaderParameterBinding[layoutBinding] =
715                         MetaData::ShaderParameterAccessor(
716                             /*name=*/glLayoutName,
717                             /*type=*/HdStGLConversions::GetGLSLTypename(
718                                 HdType::HdTypeInt32));
719 
720                     // Layout for Ptex
721                     const TfToken layoutName(_ConcatLayout(name));
722                     // used for non-bindless
723                     _bindingMap[layoutName] = layoutBinding;
724                 } else if (param.textureType == HdTextureType::Udim) {
725                     // Texture Array for UDIM
726                     HdBinding textureBinding = bindless
727                         ? HdBinding(HdBinding::BINDLESS_TEXTURE_UDIM_ARRAY,
728                                 bindlessTextureLocation++)
729                         : HdBinding(HdBinding::TEXTURE_UDIM_ARRAY,
730                                 locator.uniformLocation++,
731                                 locator.textureUnit++);
732 
733                     metaDataOut->shaderParameterBinding[textureBinding] =
734                         MetaData::ShaderParameterAccessor(
735                             /*name=*/param.name,
736                             /*type=*/glType,
737                             /*swizzle=*/glSwizzle,
738                             /*inPrimvars=*/param.samplerCoords,
739                             /*isPremultiplied=*/param.isPremultiplied);
740                     // used for non-bindless
741                     _bindingMap[param.name] = textureBinding;
742 
743                     // Layout for UDIM
744                     const TfToken layoutName(_ConcatLayout(param.name));
745 
746                     HdBinding layoutBinding = bindless
747                         ? HdBinding(HdBinding::BINDLESS_TEXTURE_UDIM_LAYOUT,
748                             bindlessTextureLocation++)
749                         : HdBinding(HdBinding::TEXTURE_UDIM_LAYOUT,
750                             locator.uniformLocation++,
751                             locator.textureUnit++);
752 
753                     metaDataOut->shaderParameterBinding[layoutBinding] =
754                         MetaData::ShaderParameterAccessor(
755                             /*name=*/layoutName,
756                             /*type=*/HdStGLConversions::GetGLSLTypename(
757                                 HdType::HdTypeFloat));
758 
759                     // used for non-bindless
760                     _bindingMap[layoutName] = layoutBinding;
761                 } else if (param.textureType == HdTextureType::Uv) {
762                     // 2d texture
763                     HdBinding textureBinding = bindless
764                         ? HdBinding(HdBinding::BINDLESS_TEXTURE_2D,
765                                     bindlessTextureLocation++)
766                         : HdBinding(HdBinding::TEXTURE_2D,
767                                     locator.uniformLocation++,
768                                     locator.textureUnit++);
769 
770                     metaDataOut->shaderParameterBinding[textureBinding] =
771                         MetaData::ShaderParameterAccessor(
772                             /*name=*/glName,
773                             /*type=*/glType,
774                             /*swizzle=*/glSwizzle,
775                             /*inPrimvars=*/param.samplerCoords,
776                             /*isPremultiplied=*/param.isPremultiplied,
777                             /*processTextureFallbackValue=*/isMaterialShader);
778                     _bindingMap[name] = textureBinding; // used for non-bindless
779                 } else if (param.textureType == HdTextureType::Field) {
780                     // 3d texture
781                     HdBinding textureBinding = bindless
782                         ? HdBinding(HdBinding::BINDLESS_TEXTURE_FIELD,
783                                     bindlessTextureLocation++)
784                         : HdBinding(HdBinding::TEXTURE_FIELD,
785                                     locator.uniformLocation++,
786                                     locator.textureUnit++);
787 
788                     metaDataOut->shaderParameterBinding[textureBinding] =
789                         MetaData::ShaderParameterAccessor(
790                             /*name=*/glName,
791                             /*type=*/glType,
792                             /*swizzle=*/glSwizzle,
793                             /*inPrimvars=*/param.samplerCoords,
794                             /*isPremultiplied=*/param.isPremultiplied,
795                             /*processTextureFallbackValue=*/isMaterialShader);
796                     _bindingMap[name] = textureBinding; // used for non-bindless
797                 }
798             } else if (param.IsPrimvarRedirect() || param.IsFieldRedirect()) {
799                 TfTokenVector const& samplePrimvars = param.samplerCoords;
800                 TfTokenVector glNames;
801                 glNames.reserve(samplePrimvars.size());
802                 for (auto const& pv : samplePrimvars) {
803                     glNames.push_back(HdStGLConversions::GetGLSLIdentifier(pv));
804                 }
805 
806                 HdBinding binding = param.IsPrimvarRedirect()
807                     ? HdBinding(HdBinding::PRIMVAR_REDIRECT,
808                                 shaderPrimvarRedirectLocation++)
809                     : HdBinding(HdBinding::FIELD_REDIRECT,
810                                 shaderFieldRedirectLocation++);
811 
812                 metaDataOut->shaderParameterBinding[binding]
813                     = MetaData::ShaderParameterAccessor(
814                     /*name=*/glName,
815                     /*type=*/glType,
816                     /*swizzle=*/glSwizzle,
817                     /*inPrimvars=*/glNames);
818             } else if (param.IsTransform2d()) {
819                 HdBinding binding = HdBinding(HdBinding::TRANSFORM_2D,
820                                               shaderTransform2dLocation++);
821                 metaDataOut->shaderParameterBinding[binding] =
822                     MetaData::ShaderParameterAccessor(
823                         /*name=*/glName,
824                         /*type=*/glType,
825                         /*swizzle=*/glSwizzle,
826                         /*inPrimvars=*/param.samplerCoords);
827             } else if (param.IsAdditionalPrimvar()) {
828                 // Additional primvars is used so certain primvars survive
829                 // primvar filtering. We can ignore them here, because primvars
830                 // found on the drawItem are already processed further above.
831             } else {
832                 TF_CODING_ERROR("Can't resolve %s", param.name.GetText());
833             }
834         }
835     }
836 
837     // Add custom bindings.
838     // Don't need to sanitize the name used, since these are internally
839     // generated.
840     TF_FOR_ALL (it, customBindings) {
841         if (it->IsInterleavedBufferArray()) {
842             // Interleaved resource, only need a single binding point
843             HdBinding binding = locator.GetBinding(it->GetBindingType(),
844                                                    it->GetName());
845             MetaData::StructBlock sblock(it->GetName());
846 
847             HdBufferArrayRangeSharedPtr bar_ = it->GetBar();
848             HdStBufferArrayRangeSharedPtr bar =
849                 std::static_pointer_cast<HdStBufferArrayRange> (bar_);
850 
851             for (auto const& nameRes : bar->GetResources()) {
852                 HdTupleType valueType = nameRes.second->GetTupleType();
853                 TfToken glType =
854                     HdStGLConversions::GetGLSLTypename(valueType.type);
855                 sblock.entries.emplace_back(nameRes.first,
856                                             glType,
857                                              nameRes.second->GetOffset(),
858                                             valueType.count);
859             }
860             metaDataOut->customInterleavedBindings.insert(
861                 std::make_pair(binding, sblock));
862             _bindingMap[it->GetName()] = binding;
863         } else {
864             // Non interleaved resource
865             typedef MetaData::BindingDeclaration BindingDeclaration;
866             if (it->IsBufferArray()) {
867                 // The BAR was provided, so we will record the name, dataType,
868                 // binding type and binding location.
869 
870                 HdBufferArrayRangeSharedPtr bar_ = it->GetBar();
871                 HdStBufferArrayRangeSharedPtr bar =
872                     std::static_pointer_cast<HdStBufferArrayRange> (bar_);
873 
874                 for (auto const& nameRes : bar->GetResources()) {
875                     HdBinding binding = locator.GetBinding(it->GetBindingType(), nameRes.first);
876                     BindingDeclaration b(nameRes.first,
877                         HdStGLConversions::GetGLSLTypename(
878                             nameRes.second->GetTupleType().type),
879                         binding);
880                     metaDataOut->customBindings.push_back(b);
881                     _bindingMap[nameRes.first] = binding;
882                 }
883             } else {
884                 HdBinding binding = locator.GetBinding(it->GetBindingType(), it->GetName());
885                 BindingDeclaration b(it->GetName(),
886                                      HdStGLConversions::GetGLSLTypename(
887                                                     it->GetDataType()),
888                                      binding);
889 
890                 // note that GetDataType() may return HdTypeInvalid,
891                 // in case it's a typeless binding. CodeGen generates
892                 // declarations and accessors only for BindingDeclaration
893                 // with a valid type.
894                 metaDataOut->customBindings.push_back(b);
895                 _bindingMap[it->GetName()] = binding;
896             }
897         }
898     }
899     _numReservedUniformBlockLocations = locator.uboLocation;
900     _numReservedTextureUnits = locator.textureUnit;
901 }
902 
903 void
ResolveComputeBindings(HdBufferSpecVector const & readWriteBufferSpecs,HdBufferSpecVector const & readOnlyBufferSpecs,HdStShaderCodeSharedPtrVector const & shaders,MetaData * metaDataOut)904 HdSt_ResourceBinder::ResolveComputeBindings(
905                     HdBufferSpecVector const &readWriteBufferSpecs,
906                     HdBufferSpecVector const &readOnlyBufferSpecs,
907                     HdStShaderCodeSharedPtrVector const &shaders,
908                     MetaData *metaDataOut)
909 {
910     HD_TRACE_FUNCTION();
911     HF_MALLOC_TAG_FUNCTION();
912 
913     if (!TF_VERIFY(metaDataOut)) {
914         return;
915     }
916 
917     // GL context caps
918     HdBinding::Type bindingType =
919         (GlfContextCaps::GetInstance().bindlessBufferEnabled
920          ? HdBinding::BINDLESS_SSBO_RANGE : HdBinding::SSBO);
921 
922     // binding assignments
923     BindingLocator locator;
924 
925     // clear all
926     _bindingMap.clear();
927 
928     // read-write per prim data
929     for (HdBufferSpec const& spec: readWriteBufferSpecs) {
930         HdBinding binding = locator.GetBinding(bindingType, spec.name);
931         _bindingMap[spec.name] = binding;
932         metaDataOut->computeReadWriteData[binding] =
933             MetaData::Primvar(spec.name,
934                               HdStGLConversions::GetGLSLTypename(
935                                              spec.tupleType.type));
936     }
937 
938     // read-only per prim data
939     for (HdBufferSpec const& spec: readOnlyBufferSpecs) {
940         HdBinding binding = locator.GetBinding(bindingType, spec.name);
941         _bindingMap[spec.name] = binding;
942         metaDataOut->computeReadOnlyData[binding] =
943             MetaData::Primvar(spec.name,
944                               HdStGLConversions::GetGLSLTypename(
945                                              spec.tupleType.type));
946     }
947 }
948 
949 void
BindBuffer(TfToken const & name,HdStBufferResourceSharedPtr const & buffer) const950 HdSt_ResourceBinder::BindBuffer(TfToken const &name,
951                               HdStBufferResourceSharedPtr const &buffer) const
952 {
953     BindBuffer(name, buffer, buffer->GetOffset(), /*level=*/-1);
954 }
955 
956 void
BindBuffer(TfToken const & name,HdStBufferResourceSharedPtr const & buffer,int offset,int level) const957 HdSt_ResourceBinder::BindBuffer(TfToken const &name,
958                               HdStBufferResourceSharedPtr const &buffer,
959                               int offset,
960                               int level) const
961 {
962     HD_TRACE_FUNCTION();
963 
964     // it is possible that the buffer has not been initialized when
965     // the instanceIndex is empty (e.g. FX points. see bug 120354)
966     if (!buffer->GetHandle()) return;
967 
968     HdBinding binding = GetBinding(name, level);
969     HdBinding::Type type = binding.GetType();
970     int loc              = binding.GetLocation();
971 
972     HdTupleType tupleType = buffer->GetTupleType();
973 
974     void const* offsetPtr =
975         reinterpret_cast<const void*>(
976             static_cast<intptr_t>(offset));
977     switch(type) {
978     case HdBinding::VERTEX_ATTR:
979         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetHandle()->GetRawResource());
980         glVertexAttribPointer(loc,
981                   _GetNumComponents(tupleType.type),
982                   HdStGLConversions::GetGLAttribType(tupleType.type),
983                   _ShouldBeNormalized(tupleType.type),
984                               buffer->GetStride(),
985                               offsetPtr);
986         glBindBuffer(GL_ARRAY_BUFFER, 0);
987 
988         glEnableVertexAttribArray(loc);
989         break;
990     case HdBinding::DRAW_INDEX:
991         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetHandle()->GetRawResource());
992         glVertexAttribIPointer(loc,
993                                HdGetComponentCount(tupleType.type),
994                                GL_INT,
995                                buffer->GetStride(),
996                                offsetPtr);
997         glBindBuffer(GL_ARRAY_BUFFER, 0);
998         glEnableVertexAttribArray(loc);
999         break;
1000     case HdBinding::DRAW_INDEX_INSTANCE:
1001         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetHandle()->GetRawResource());
1002         glVertexAttribIPointer(loc,
1003                                HdGetComponentCount(tupleType.type),
1004                                GL_INT,
1005                                buffer->GetStride(),
1006                                offsetPtr);
1007         glBindBuffer(GL_ARRAY_BUFFER, 0);
1008 
1009         // set the divisor to uint-max so that the same base value is used
1010         // for all instances.
1011         glVertexAttribDivisor(loc,
1012                               std::numeric_limits<GLint>::max());
1013         glEnableVertexAttribArray(loc);
1014         break;
1015     case HdBinding::DRAW_INDEX_INSTANCE_ARRAY:
1016         glBindBuffer(GL_ARRAY_BUFFER, buffer->GetHandle()->GetRawResource());
1017         // instancerNumLevels is represented by the tuple size.
1018         // We unroll this to an array of int[1] attributes.
1019         for (size_t i = 0; i < buffer->GetTupleType().count; ++i) {
1020             offsetPtr = reinterpret_cast<const void*>(offset + i*sizeof(int));
1021             glVertexAttribIPointer(loc, 1, GL_INT, buffer->GetStride(),
1022                                    offsetPtr);
1023             // set the divisor to uint-max so that the same base value is used
1024             // for all instances.
1025             glVertexAttribDivisor(loc, std::numeric_limits<GLint>::max());
1026             glEnableVertexAttribArray(loc);
1027             ++loc;
1028         }
1029         glBindBuffer(GL_ARRAY_BUFFER, 0);
1030         break;
1031     case HdBinding::INDEX_ATTR:
1032         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
1033                      buffer->GetHandle()->GetRawResource());
1034         break;
1035     case HdBinding::BINDLESS_UNIFORM:
1036         // at least in nvidia driver 346.59, this query call doesn't show
1037         // any pipeline stall.
1038         if (!glIsNamedBufferResidentNV(buffer->GetHandle()->GetRawResource())) {
1039             glMakeNamedBufferResidentNV(
1040                 buffer->GetHandle()->GetRawResource(), GL_READ_WRITE);
1041         }
1042         {
1043             HgiGLBuffer * bufferGL =
1044                 static_cast<HgiGLBuffer*>(buffer->GetHandle().Get());
1045             glUniformui64NV(loc, bufferGL->GetBindlessGPUAddress());
1046         }
1047         break;
1048     case HdBinding::SSBO:
1049         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, loc,
1050                          buffer->GetHandle()->GetRawResource());
1051         break;
1052     case HdBinding::BINDLESS_SSBO_RANGE:
1053         // at least in nvidia driver 346.59, this query call doesn't show
1054         // any pipeline stall.
1055         if (!glIsNamedBufferResidentNV(buffer->GetHandle()->GetRawResource())) {
1056             glMakeNamedBufferResidentNV(
1057                 buffer->GetHandle()->GetRawResource(), GL_READ_WRITE);
1058         }
1059         {
1060             HgiGLBuffer * bufferGL =
1061                 static_cast<HgiGLBuffer*>(buffer->GetHandle().Get());
1062             glUniformui64NV(loc, bufferGL->GetBindlessGPUAddress()+offset);
1063         }
1064         break;
1065     case HdBinding::DISPATCH:
1066         glBindBuffer(GL_DRAW_INDIRECT_BUFFER,
1067                      buffer->GetHandle()->GetRawResource());
1068         break;
1069     case HdBinding::UBO:
1070     case HdBinding::UNIFORM:
1071         glBindBufferRange(GL_UNIFORM_BUFFER, loc,
1072                           buffer->GetHandle()->GetRawResource(),
1073                           offset,
1074                           buffer->GetStride());
1075         break;
1076     case HdBinding::TEXTURE_2D:
1077     case HdBinding::TEXTURE_FIELD:
1078         // nothing
1079         break;
1080     default:
1081         TF_CODING_ERROR("binding type %d not found for %s",
1082                         type, name.GetText());
1083         break;
1084     }
1085 }
1086 
1087 void
UnbindBuffer(TfToken const & name,HdStBufferResourceSharedPtr const & buffer,int level) const1088 HdSt_ResourceBinder::UnbindBuffer(TfToken const &name,
1089                                 HdStBufferResourceSharedPtr const &buffer,
1090                                 int level) const
1091 {
1092     HD_TRACE_FUNCTION();
1093 
1094     // it is possible that the buffer has not been initialized when
1095     // the instanceIndex is empty (e.g. FX points)
1096     if (!buffer->GetHandle()) return;
1097 
1098     HdBinding binding = GetBinding(name, level);
1099     HdBinding::Type type = binding.GetType();
1100     int loc = binding.GetLocation();
1101 
1102     switch(type) {
1103     case HdBinding::VERTEX_ATTR:
1104         glDisableVertexAttribArray(loc);
1105         break;
1106     case HdBinding::DRAW_INDEX:
1107         glDisableVertexAttribArray(loc);
1108         break;
1109     case HdBinding::DRAW_INDEX_INSTANCE:
1110         glDisableVertexAttribArray(loc);
1111         glVertexAttribDivisor(loc, 0);
1112         break;
1113     case HdBinding::DRAW_INDEX_INSTANCE_ARRAY:
1114         // instancerNumLevels is represented by the tuple size.
1115         for (size_t i = 0; i < buffer->GetTupleType().count; ++i) {
1116             glDisableVertexAttribArray(loc);
1117             glVertexAttribDivisor(loc, 0);
1118             ++loc;
1119         }
1120         break;
1121     case HdBinding::INDEX_ATTR:
1122         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1123         break;
1124     case HdBinding::BINDLESS_UNIFORM:
1125         if (glIsNamedBufferResidentNV(buffer->GetHandle()->GetRawResource())) {
1126             glMakeNamedBufferNonResidentNV(
1127                 buffer->GetHandle()->GetRawResource());
1128         }
1129         break;
1130     case HdBinding::SSBO:
1131         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, loc, 0);
1132         break;
1133     case HdBinding::BINDLESS_SSBO_RANGE:
1134         if (glIsNamedBufferResidentNV(buffer->GetHandle()->GetRawResource())) {
1135             glMakeNamedBufferNonResidentNV(
1136                 buffer->GetHandle()->GetRawResource());
1137         }
1138         break;
1139     case HdBinding::DISPATCH:
1140         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
1141         break;
1142     case HdBinding::UBO:
1143     case HdBinding::UNIFORM:
1144         glBindBufferBase(GL_UNIFORM_BUFFER, loc, 0);
1145         break;
1146     case HdBinding::TEXTURE_2D:
1147     case HdBinding::TEXTURE_FIELD:
1148         // nothing
1149         break;
1150     default:
1151         TF_CODING_ERROR("binding type %d not found for %s",
1152                         type, name.GetText());
1153         break;
1154     }
1155 }
1156 
1157 void
BindConstantBuffer(HdStBufferArrayRangeSharedPtr const & constantBar) const1158 HdSt_ResourceBinder::BindConstantBuffer(
1159     HdStBufferArrayRangeSharedPtr const &constantBar) const
1160 {
1161     if (!constantBar) return;
1162 
1163     // constant buffer is interleaved. we just need to bind a buffer.
1164     BindBuffer(_tokens->constantPrimvars, constantBar->GetResource());
1165 }
1166 
1167 void
UnbindConstantBuffer(HdStBufferArrayRangeSharedPtr const & constantBar) const1168 HdSt_ResourceBinder::UnbindConstantBuffer(
1169     HdStBufferArrayRangeSharedPtr const &constantBar) const
1170 {
1171     if (!constantBar) return;
1172 
1173     UnbindBuffer(_tokens->constantPrimvars, constantBar->GetResource());
1174 }
1175 
1176 void
BindInterleavedBuffer(HdStBufferArrayRangeSharedPtr const & interleavedBar,TfToken const & name) const1177 HdSt_ResourceBinder::BindInterleavedBuffer(
1178     HdStBufferArrayRangeSharedPtr const &interleavedBar,
1179     TfToken const &name) const
1180 {
1181     if (!interleavedBar) return;
1182 
1183     BindBuffer(name, interleavedBar->GetResource());
1184 }
1185 
1186 void
UnbindInterleavedBuffer(HdStBufferArrayRangeSharedPtr const & interleavedBar,TfToken const & name) const1187 HdSt_ResourceBinder::UnbindInterleavedBuffer(
1188     HdStBufferArrayRangeSharedPtr const &interleavedBar,
1189     TfToken const &name) const
1190 {
1191     if (!interleavedBar) return;
1192 
1193     UnbindBuffer(name, interleavedBar->GetResource());
1194 }
1195 
1196 void
BindInstanceBufferArray(HdStBufferArrayRangeSharedPtr const & bar,int level) const1197 HdSt_ResourceBinder::BindInstanceBufferArray(
1198     HdStBufferArrayRangeSharedPtr const &bar, int level) const
1199 {
1200     if (!bar) return;
1201 
1202     TF_FOR_ALL(it, bar->GetResources()) {
1203         if (HasBinding(it->first, level)) {
1204             BindBuffer(it->first, it->second, it->second->GetOffset(), level);
1205         }
1206     }
1207 }
1208 
1209 void
UnbindInstanceBufferArray(HdStBufferArrayRangeSharedPtr const & bar,int level) const1210 HdSt_ResourceBinder::UnbindInstanceBufferArray(
1211     HdStBufferArrayRangeSharedPtr const &bar, int level) const
1212 {
1213     if (!bar) return;
1214 
1215     TF_FOR_ALL(it, bar->GetResources()) {
1216         if (HasBinding(it->first, level)) {
1217             UnbindBuffer(it->first, it->second, level);
1218         }
1219     }
1220 }
1221 
1222 void
BindShaderResources(HdStShaderCode const * shader) const1223 HdSt_ResourceBinder::BindShaderResources(HdStShaderCode const *shader) const
1224 {
1225 }
1226 
1227 void
UnbindShaderResources(HdStShaderCode const * shader) const1228 HdSt_ResourceBinder::UnbindShaderResources(HdStShaderCode const *shader) const
1229 {
1230 }
1231 
1232 void
BindBufferArray(HdStBufferArrayRangeSharedPtr const & bar) const1233 HdSt_ResourceBinder::BindBufferArray(HdStBufferArrayRangeSharedPtr const &bar) const
1234 {
1235     if (!bar) return;
1236 
1237     TF_FOR_ALL(it, bar->GetResources()) {
1238         BindBuffer(it->first, it->second);
1239     }
1240 }
1241 
1242 void
Bind(HdBindingRequest const & req) const1243 HdSt_ResourceBinder::Bind(HdBindingRequest const& req) const
1244 {
1245     if (req.IsTypeless()) {
1246         return;
1247     } else if (req.IsResource()) {
1248         HdBufferResourceSharedPtr res_ = req.GetResource();
1249         HdStBufferResourceSharedPtr res =
1250             std::static_pointer_cast<HdStBufferResource> (res_);
1251 
1252         BindBuffer(req.GetName(), res, req.GetByteOffset());
1253     } else if (req.IsInterleavedBufferArray()) {
1254         // note: interleaved buffer needs only 1 binding
1255         HdBufferArrayRangeSharedPtr bar_ = req.GetBar();
1256         HdStBufferArrayRangeSharedPtr bar =
1257             std::static_pointer_cast<HdStBufferArrayRange> (bar_);
1258         BindBuffer(req.GetName(), bar->GetResource(), req.GetByteOffset());
1259     } else if (req.IsBufferArray()) {
1260         HdBufferArrayRangeSharedPtr bar_ = req.GetBar();
1261         HdStBufferArrayRangeSharedPtr bar =
1262             std::static_pointer_cast<HdStBufferArrayRange> (bar_);
1263         BindBufferArray(bar);
1264     }
1265 }
1266 
1267 void
Unbind(HdBindingRequest const & req) const1268 HdSt_ResourceBinder::Unbind(HdBindingRequest const& req) const
1269 {
1270     if (req.IsTypeless()) {
1271         return;
1272     } else if (req.IsResource()) {
1273         HdBufferResourceSharedPtr res_ = req.GetResource();
1274         HdStBufferResourceSharedPtr res =
1275             std::static_pointer_cast<HdStBufferResource> (res_);
1276 
1277         UnbindBuffer(req.GetName(), res);
1278     } else if (req.IsInterleavedBufferArray()) {
1279         // note: interleaved buffer needs only 1 binding
1280         HdBufferArrayRangeSharedPtr bar_ = req.GetBar();
1281         HdStBufferArrayRangeSharedPtr bar =
1282             std::static_pointer_cast<HdStBufferArrayRange> (bar_);
1283 
1284         UnbindBuffer(req.GetName(), bar->GetResource());
1285     } else if (req.IsBufferArray()) {
1286         HdBufferArrayRangeSharedPtr bar_ = req.GetBar();
1287         HdStBufferArrayRangeSharedPtr bar =
1288             std::static_pointer_cast<HdStBufferArrayRange> (bar_);
1289 
1290         UnbindBufferArray(bar);
1291     }
1292 }
1293 
1294 void
UnbindBufferArray(HdStBufferArrayRangeSharedPtr const & bar) const1295 HdSt_ResourceBinder::UnbindBufferArray(
1296     HdStBufferArrayRangeSharedPtr const &bar) const
1297 {
1298     if (!bar) return;
1299 
1300     TF_FOR_ALL(it, bar->GetResources()) {
1301         UnbindBuffer(it->first, it->second);
1302     }
1303 }
1304 
1305 void
BindUniformi(TfToken const & name,int count,const int * value) const1306 HdSt_ResourceBinder::BindUniformi(TfToken const &name,
1307                                 int count, const int *value) const
1308 {
1309     HdBinding uniformLocation = GetBinding(name);
1310     if (uniformLocation.GetLocation() == HdBinding::NOT_EXIST) return;
1311 
1312     TF_VERIFY(uniformLocation.IsValid());
1313     TF_VERIFY(uniformLocation.GetType() == HdBinding::UNIFORM);
1314 
1315     if (count == 1) {
1316         glUniform1iv(uniformLocation.GetLocation(), 1, value);
1317     } else if (count == 2) {
1318         glUniform2iv(uniformLocation.GetLocation(), 1, value);
1319     } else if (count == 3) {
1320         glUniform3iv(uniformLocation.GetLocation(), 1, value);
1321     } else if (count == 4) {
1322         glUniform4iv(uniformLocation.GetLocation(), 1, value);
1323     } else {
1324         TF_CODING_ERROR("Invalid count %d.\n", count);
1325     }
1326 }
1327 
1328 void
BindUniformArrayi(TfToken const & name,int count,const int * value) const1329 HdSt_ResourceBinder::BindUniformArrayi(TfToken const &name,
1330                                  int count, const int *value) const
1331 {
1332     HdBinding uniformLocation = GetBinding(name);
1333     if (uniformLocation.GetLocation() == HdBinding::NOT_EXIST) return;
1334 
1335     TF_VERIFY(uniformLocation.IsValid());
1336     TF_VERIFY(uniformLocation.GetType() == HdBinding::UNIFORM_ARRAY);
1337 
1338     glUniform1iv(uniformLocation.GetLocation(), count, value);
1339 }
1340 
1341 void
BindUniformui(TfToken const & name,int count,const unsigned int * value) const1342 HdSt_ResourceBinder::BindUniformui(TfToken const &name,
1343                                 int count, const unsigned int *value) const
1344 {
1345     HdBinding uniformLocation = GetBinding(name);
1346     if (uniformLocation.GetLocation() == HdBinding::NOT_EXIST) return;
1347 
1348     TF_VERIFY(uniformLocation.IsValid());
1349     TF_VERIFY(uniformLocation.GetType() == HdBinding::UNIFORM);
1350 
1351     if (count == 1) {
1352         glUniform1uiv(uniformLocation.GetLocation(), 1, value);
1353     } else if (count == 2) {
1354         glUniform2uiv(uniformLocation.GetLocation(), 1, value);
1355     } else if (count == 3) {
1356         glUniform3uiv(uniformLocation.GetLocation(), 1, value);
1357     } else if (count == 4) {
1358         glUniform4uiv(uniformLocation.GetLocation(), 1, value);
1359     } else {
1360         TF_CODING_ERROR("Invalid count %d.", count);
1361     }
1362 }
1363 
1364 void
BindUniformf(TfToken const & name,int count,const float * value) const1365 HdSt_ResourceBinder::BindUniformf(TfToken const &name,
1366                                 int count, const float *value) const
1367 {
1368     HdBinding uniformLocation = GetBinding(name);
1369     if (uniformLocation.GetLocation() == HdBinding::NOT_EXIST) return;
1370 
1371     if (!TF_VERIFY(uniformLocation.IsValid())) return;
1372     if (!TF_VERIFY(uniformLocation.GetType() == HdBinding::UNIFORM)) return;
1373     GLint location = uniformLocation.GetLocation();
1374 
1375     if (count == 1) {
1376         glUniform1fv(location, 1, value);
1377     } else if (count == 2) {
1378         glUniform2fv(location, 1, value);
1379     } else if (count == 3) {
1380         glUniform3fv(location, 1, value);
1381     } else if (count == 4) {
1382         glUniform4fv(location, 1, value);
1383     } else if (count == 16) {
1384         glUniformMatrix4fv(location, 1, /*transpose=*/false, value);
1385     } else {
1386         TF_CODING_ERROR("Invalid count %d.", count);
1387     }
1388 }
1389 
1390 void
IntrospectBindings(HgiShaderProgramHandle const & hgiProgram)1391 HdSt_ResourceBinder::IntrospectBindings(HgiShaderProgramHandle const & hgiProgram)
1392 {
1393     GlfContextCaps const &caps = GlfContextCaps::GetInstance();
1394 
1395     GLuint program = hgiProgram->GetRawResource();
1396 
1397     if (ARCH_UNLIKELY(!caps.shadingLanguage420pack)) {
1398         GLint numUBO = 0;
1399         glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numUBO);
1400 
1401         const int MAX_NAME = 256;
1402         int length = 0;
1403         char name[MAX_NAME+1];
1404         for (int i = 0; i < numUBO; ++i) {
1405             glGetActiveUniformBlockName(program, i, MAX_NAME, &length, name);
1406             // note: ubo_ prefix is added in HdCodeGen::_EmitDeclaration()
1407             if (strstr(name, "ubo_") == name) {
1408                 HdBinding binding;
1409                 if (TfMapLookup(_bindingMap, NameAndLevel(TfToken(name+4)), &binding)) {
1410                     // set uniform block binding.
1411                     glUniformBlockBinding(program, i, binding.GetLocation());
1412                 }
1413             }
1414         }
1415     }
1416 
1417     if (ARCH_UNLIKELY(!caps.explicitUniformLocation)) {
1418         for (auto & it: _bindingMap) {
1419             HdBinding binding = it.second;
1420             HdBinding::Type type = binding.GetType();
1421             std::string name = it.first.name;
1422             int level = it.first.level;
1423             if (level >=0) {
1424                 // follow nested instancing naming convention.
1425                 std::stringstream n;
1426                 n << name << "_" << level;
1427                 name = n.str();
1428             }
1429             if (type == HdBinding::UNIFORM       ||
1430                 type == HdBinding::UNIFORM_ARRAY) {
1431                 GLint loc = glGetUniformLocation(program, name.c_str());
1432                 // update location in resource binder.
1433                 // some uniforms may be optimized out.
1434                 if (loc < 0) loc = HdBinding::NOT_EXIST;
1435                 it.second.Set(type, loc, binding.GetTextureUnit());
1436             }
1437         }
1438     }
1439 
1440     if (ARCH_UNLIKELY(!caps.shadingLanguage420pack)) {
1441         for (auto & it: _bindingMap) {
1442             HdBinding binding = it.second;
1443             HdBinding::Type type = binding.GetType();
1444             std::string name = it.first.name;
1445             std::string textureName;
1446 
1447             // note: sampler prefix is added in
1448             // HdCodeGen::_GenerateShaderParameters
1449             if (type == HdBinding::TEXTURE_2D) {
1450                 textureName = "sampler2d_" + name;
1451             } else if (type == HdBinding::TEXTURE_FIELD) {
1452                 textureName = "sampler3d_" + name;
1453             } else if (type == HdBinding::TEXTURE_PTEX_TEXEL) {
1454                 textureName = "sampler2darray_" + name;
1455             } else if (type == HdBinding::TEXTURE_PTEX_LAYOUT) {
1456                 textureName = "isampler1darray_" + name;
1457             } else if (type == HdBinding::TEXTURE_UDIM_ARRAY) {
1458                 textureName = "sampler2dArray_" + name;
1459             } else if (type == HdBinding::TEXTURE_UDIM_LAYOUT) {
1460                 textureName = "sampler1d_" + name;
1461             }
1462 
1463             if (!textureName.empty()) {
1464                 GLint loc = glGetUniformLocation(program, textureName.c_str());
1465                 glProgramUniform1i(program, loc, binding.GetTextureUnit());
1466                 if (loc < 0) loc = HdBinding::NOT_EXIST;
1467                 it.second.Set(type, loc, binding.GetTextureUnit());
1468             }
1469         }
1470     }
1471 }
1472 
1473 HdSt_ResourceBinder::MetaData::ID
ComputeHash() const1474 HdSt_ResourceBinder::MetaData::ComputeHash() const
1475 {
1476     ID hash = 0;
1477 
1478     boost::hash_combine(hash, drawingCoord0Binding.binding.GetValue());
1479     boost::hash_combine(hash, drawingCoord0Binding.dataType);
1480     boost::hash_combine(hash, drawingCoord1Binding.binding.GetValue());
1481     boost::hash_combine(hash, drawingCoord1Binding.dataType);
1482     boost::hash_combine(hash, drawingCoord2Binding.binding.GetValue());
1483     boost::hash_combine(hash, drawingCoord2Binding.dataType);
1484     boost::hash_combine(hash, drawingCoordIBinding.binding.GetValue());
1485     boost::hash_combine(hash, drawingCoordIBinding.dataType);
1486     boost::hash_combine(hash, instanceIndexArrayBinding.binding.GetValue());
1487     boost::hash_combine(hash, instanceIndexArrayBinding.dataType);
1488     boost::hash_combine(hash, instanceIndexBaseBinding.binding.GetValue());
1489     boost::hash_combine(hash, instanceIndexBaseBinding.dataType);
1490     boost::hash_combine(hash, primitiveParamBinding.binding.GetValue());
1491     boost::hash_combine(hash, primitiveParamBinding.dataType);
1492     boost::hash_combine(hash, edgeIndexBinding.binding.GetValue());
1493     boost::hash_combine(hash, edgeIndexBinding.dataType);
1494     boost::hash_combine(hash, coarseFaceIndexBinding.binding.GetValue());
1495     boost::hash_combine(hash, coarseFaceIndexBinding.dataType);
1496 
1497     TF_FOR_ALL(binDecl, fvarIndicesBindings) {
1498         boost::hash_combine(hash, binDecl->binding.GetValue());
1499         boost::hash_combine(hash, binDecl->dataType);
1500     }
1501     TF_FOR_ALL(binDecl, fvarPatchParamBindings) {
1502         boost::hash_combine(hash, binDecl->binding.GetValue());
1503         boost::hash_combine(hash, binDecl->dataType);
1504     }
1505 
1506     // separators are inserted to distinguish primvars have a same layout
1507     // but different interpolation.
1508     boost::hash_combine(hash, 0); // separator
1509     TF_FOR_ALL(binDecl, customBindings) {
1510         boost::hash_combine(hash, binDecl->name.Hash());
1511         boost::hash_combine(hash, binDecl->dataType);
1512         boost::hash_combine(hash, binDecl->binding.GetType());
1513         boost::hash_combine(hash, binDecl->binding.GetLocation());
1514     }
1515 
1516     boost::hash_combine(hash, 0); // separator
1517     TF_FOR_ALL(blockIt, customInterleavedBindings) {
1518         boost::hash_combine(hash, (int)blockIt->first.GetType()); // binding
1519         TF_FOR_ALL (it, blockIt->second.entries) {
1520             StructEntry const &entry = *it;
1521             boost::hash_combine(hash, entry.name.Hash());
1522             boost::hash_combine(hash, entry.dataType);
1523             boost::hash_combine(hash, entry.offset);
1524             boost::hash_combine(hash, entry.arraySize);
1525         }
1526     }
1527 
1528     boost::hash_combine(hash, 0); // separator
1529     TF_FOR_ALL (blockIt, constantData) {
1530         boost::hash_combine(hash, (int)blockIt->first.GetType()); // binding
1531         TF_FOR_ALL (it, blockIt->second.entries) {
1532             StructEntry const &entry = *it;
1533             boost::hash_combine(hash, entry.name.Hash());
1534             boost::hash_combine(hash, entry.dataType);
1535             boost::hash_combine(hash, entry.offset);
1536             boost::hash_combine(hash, entry.arraySize);
1537         }
1538     }
1539 
1540     boost::hash_combine(hash, 0); // separator
1541     TF_FOR_ALL (blockIt, topologyVisibilityData) {
1542         boost::hash_combine(hash, (int)blockIt->first.GetType()); // binding
1543         TF_FOR_ALL (it, blockIt->second.entries) {
1544             StructEntry const &entry = *it;
1545             boost::hash_combine(hash, entry.name.Hash());
1546             boost::hash_combine(hash, entry.dataType);
1547             boost::hash_combine(hash, entry.offset);
1548             boost::hash_combine(hash, entry.arraySize);
1549         }
1550     }
1551 
1552     boost::hash_combine(hash, 0); // separator
1553     TF_FOR_ALL (it, instanceData) {
1554         boost::hash_combine(hash, (int)it->first.GetType()); // binding
1555         NestedPrimvar const &primvar = it->second;
1556         boost::hash_combine(hash, primvar.name.Hash());
1557         boost::hash_combine(hash, primvar.dataType);
1558         boost::hash_combine(hash, primvar.level);
1559     }
1560     boost::hash_combine(hash, 0); // separator
1561     TF_FOR_ALL (it, vertexData) {
1562         boost::hash_combine(hash, (int)it->first.GetType()); // binding
1563         Primvar const &primvar = it->second;
1564         boost::hash_combine(hash, primvar.name.Hash());
1565         boost::hash_combine(hash, primvar.dataType);
1566     }
1567     boost::hash_combine(hash, 0); // separator
1568     TF_FOR_ALL (it, varyingData) {
1569         boost::hash_combine(hash, (int)it->first.GetType()); // binding
1570         Primvar const &primvar = it->second;
1571         boost::hash_combine(hash, primvar.name.Hash());
1572         boost::hash_combine(hash, primvar.dataType);
1573     }
1574     boost::hash_combine(hash, 0); // separator
1575     TF_FOR_ALL (it, elementData) {
1576         boost::hash_combine(hash, (int)it->first.GetType()); // binding
1577         Primvar const &primvar = it->second;
1578         boost::hash_combine(hash, primvar.name.Hash());
1579         boost::hash_combine(hash, primvar.dataType);
1580     }
1581     boost::hash_combine(hash, 0); // separator
1582     TF_FOR_ALL (it, fvarData) {
1583         boost::hash_combine(hash, (int)it->first.GetType()); // binding
1584         FvarPrimvar const &primvar = it->second;
1585         boost::hash_combine(hash, primvar.name.Hash());
1586         boost::hash_combine(hash, primvar.dataType);
1587         boost::hash_combine(hash, primvar.channel);
1588     }
1589     boost::hash_combine(hash, 0); // separator
1590     TF_FOR_ALL (blockIt, shaderData) {
1591         boost::hash_combine(hash, (int)blockIt->first.GetType()); // binding
1592         TF_FOR_ALL (it, blockIt->second.entries) {
1593             StructEntry const &entry = *it;
1594             boost::hash_combine(hash, entry.name.Hash());
1595             boost::hash_combine(hash, entry.dataType);
1596             boost::hash_combine(hash, entry.offset);
1597             boost::hash_combine(hash, entry.arraySize);
1598         }
1599     }
1600     boost::hash_combine(hash, 0); // separator
1601     TF_FOR_ALL (it, shaderParameterBinding) {
1602         boost::hash_combine(hash, (int)it->first.GetType()); // binding
1603         ShaderParameterAccessor const &entry = it->second;
1604         boost::hash_combine(hash, entry.name.Hash());
1605         boost::hash_combine(hash, entry.dataType);
1606         boost::hash_combine(hash, entry.swizzle);
1607     }
1608 
1609     return hash;
1610 }
1611 
1612 /* static */
1613 bool
UseBindlessHandles()1614 HdSt_ResourceBinder::UseBindlessHandles()
1615 {
1616     return GlfContextCaps::GetInstance().bindlessTextureEnabled;
1617 }
1618 
1619 /* static */
1620 uint64_t
GetSamplerBindlessHandle(HgiSamplerHandle const & samplerHandle,HgiTextureHandle const & textureHandle)1621 HdSt_ResourceBinder::GetSamplerBindlessHandle(
1622         HgiSamplerHandle const &samplerHandle,
1623         HgiTextureHandle const &textureHandle)
1624 {
1625     HgiGLSampler * const glSampler =
1626         const_cast<HgiGLSampler*>(
1627         dynamic_cast<const HgiGLSampler*>(samplerHandle.Get()));
1628 
1629     HgiGLTexture * const glTexture =
1630         const_cast<HgiGLTexture*>(
1631         dynamic_cast<const HgiGLTexture*>(textureHandle.Get()));
1632 
1633     if (!glSampler || !glTexture) {
1634         return 0;
1635     }
1636 
1637     return glSampler->GetBindlessHandle(textureHandle);
1638 }
1639 
1640 /* static */
1641 uint64_t
GetTextureBindlessHandle(HgiTextureHandle const & textureHandle)1642 HdSt_ResourceBinder::GetTextureBindlessHandle(
1643         HgiTextureHandle const &textureHandle)
1644 {
1645     HgiGLTexture * const glTexture =
1646         const_cast<HgiGLTexture*>(
1647         dynamic_cast<const HgiGLTexture*>(textureHandle.Get()));
1648 
1649     if (!glTexture) {
1650         return 0;
1651     }
1652 
1653     return glTexture->GetBindlessHandle();
1654 }
1655 
1656 static
1657 bool
_IsBindless(HdBinding const & binding)1658 _IsBindless(HdBinding const & binding)
1659 {
1660     switch (binding.GetType()) {
1661         case HdBinding::BINDLESS_TEXTURE_2D:
1662         case HdBinding::BINDLESS_TEXTURE_FIELD:
1663         case HdBinding::BINDLESS_TEXTURE_UDIM_ARRAY:
1664         case HdBinding::BINDLESS_TEXTURE_UDIM_LAYOUT:
1665         case HdBinding::BINDLESS_TEXTURE_PTEX_TEXEL:
1666         case HdBinding::BINDLESS_TEXTURE_PTEX_LAYOUT:
1667             return true;
1668         default:
1669             return false;;
1670     }
1671 }
1672 
1673 static
1674 GLenum
_GetTextureTarget(HdBinding const & binding)1675 _GetTextureTarget(HdBinding const & binding)
1676 {
1677     switch (binding.GetType()) {
1678         case HdBinding::TEXTURE_2D:
1679             return GL_TEXTURE_2D;
1680         case HdBinding::TEXTURE_FIELD:
1681             return GL_TEXTURE_3D;
1682         case HdBinding::TEXTURE_UDIM_ARRAY:
1683         case HdBinding::TEXTURE_PTEX_TEXEL:
1684             return GL_TEXTURE_2D_ARRAY;
1685         case HdBinding::TEXTURE_UDIM_LAYOUT:
1686             return GL_TEXTURE_1D;
1687         case HdBinding::TEXTURE_PTEX_LAYOUT:
1688             return GL_TEXTURE_1D_ARRAY;
1689         default:
1690             TF_CODING_ERROR("Unknown texture binding type");
1691             return GL_NONE;
1692     }
1693 }
1694 
1695 void
BindTexture(const TfToken & name,HgiSamplerHandle const & samplerHandle,HgiTextureHandle const & textureHandle,const bool bind) const1696 HdSt_ResourceBinder::BindTexture(
1697         const TfToken &name,
1698         HgiSamplerHandle const &samplerHandle,
1699         HgiTextureHandle const &textureHandle,
1700         const bool bind) const
1701 {
1702     const HdBinding binding = GetBinding(name);
1703     if (_IsBindless(binding)) {
1704         return;
1705     }
1706 
1707     const int samplerUnit = binding.GetTextureUnit();
1708 
1709     glActiveTexture(GL_TEXTURE0 + samplerUnit);
1710 
1711     const HgiTexture * const tex = textureHandle.Get();
1712     const HgiGLTexture * const glTex =
1713         dynamic_cast<const HgiGLTexture*>(tex);
1714 
1715     if (tex && !glTex) {
1716         TF_CODING_ERROR("Resource binder only supports OpenGL");
1717     }
1718 
1719     const GLuint texName =
1720         (bind && glTex) ? glTex->GetTextureId() : 0;
1721     glBindTexture(_GetTextureTarget(binding), texName);
1722 
1723     const HgiSampler * const sampler = samplerHandle.Get();
1724     const HgiGLSampler * const glSampler =
1725         dynamic_cast<const HgiGLSampler*>(sampler);
1726 
1727     if (sampler && !glSampler) {
1728         TF_CODING_ERROR("Resource binder only supports OpenGL");
1729     }
1730 
1731     const GLuint samplerName =
1732         (bind && glSampler) ? glSampler->GetSamplerId() : 0;
1733     glBindSampler(samplerUnit, samplerName);
1734 
1735     glActiveTexture(GL_TEXTURE0);
1736 }
1737 
1738 void
BindTextureWithLayout(TfToken const & name,HgiSamplerHandle const & texelSampler,HgiTextureHandle const & texelTexture,HgiTextureHandle const & layoutTexture,const bool bind) const1739 HdSt_ResourceBinder::BindTextureWithLayout(
1740         TfToken const &name,
1741         HgiSamplerHandle const &texelSampler,
1742         HgiTextureHandle const &texelTexture,
1743         HgiTextureHandle const &layoutTexture,
1744         const bool bind) const
1745 {
1746     const HdBinding texelBinding = GetBinding(name);
1747     if (_IsBindless(texelBinding)) {
1748         return;
1749     }
1750 
1751     const int texelSamplerUnit = texelBinding.GetTextureUnit();
1752 
1753     glActiveTexture(GL_TEXTURE0 + texelSamplerUnit);
1754     glBindTexture(_GetTextureTarget(texelBinding),
1755               (bind && texelTexture) ? texelTexture->GetRawResource() : 0);
1756 
1757     const HgiGLSampler * const glSampler =
1758         bind ? dynamic_cast<HgiGLSampler*>(texelSampler.Get()) : nullptr;
1759 
1760     if (glSampler) {
1761         glBindSampler(texelSamplerUnit, (GLuint)glSampler->GetSamplerId());
1762     } else {
1763         glBindSampler(texelSamplerUnit, 0);
1764     }
1765 
1766     const HdBinding layoutBinding = GetBinding(_ConcatLayout(name));
1767     const int layoutSamplerUnit = layoutBinding.GetTextureUnit();
1768 
1769     glActiveTexture(GL_TEXTURE0 + layoutSamplerUnit);
1770     glBindTexture(_GetTextureTarget(layoutBinding),
1771               (bind && layoutTexture) ? layoutTexture->GetRawResource() : 0);
1772     glActiveTexture(GL_TEXTURE0);
1773 }
1774 
1775 
1776 PXR_NAMESPACE_CLOSE_SCOPE
1777