1 //
2 // Copyright 2019 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/hdSt/volume.h"
25 
26 #include "pxr/imaging/hdSt/drawItem.h"
27 #include "pxr/imaging/hdSt/field.h"
28 #include "pxr/imaging/hdSt/material.h"
29 #include "pxr/imaging/hdSt/materialNetworkShader.h"
30 #include "pxr/imaging/hdSt/materialParam.h"
31 #include "pxr/imaging/hdSt/package.h"
32 #include "pxr/imaging/hdSt/primUtils.h"
33 #include "pxr/imaging/hdSt/renderParam.h"
34 #include "pxr/imaging/hdSt/resourceBinder.h"
35 #include "pxr/imaging/hdSt/resourceRegistry.h"
36 #include "pxr/imaging/hdSt/textureBinder.h"
37 #include "pxr/imaging/hdSt/tokens.h"
38 #include "pxr/imaging/hdSt/volumeShader.h"
39 #include "pxr/imaging/hdSt/volumeShaderKey.h"
40 
41 #include "pxr/imaging/hd/sceneDelegate.h"
42 #include "pxr/imaging/hd/vtBufferSource.h"
43 
44 #include "pxr/imaging/hf/diagnostic.h"
45 
46 #include "pxr/imaging/hio/glslfx.h"
47 
48 #include "pxr/base/tf/staticTokens.h"
49 
50 PXR_NAMESPACE_OPEN_SCOPE
51 
52 TF_DEFINE_PRIVATE_TOKENS(
53     _fallbackShaderTokens,
54 
55     (density)
56     (emission)
57 );
58 
59 const float HdStVolume::defaultStepSize                 =   1.0f;
60 const float HdStVolume::defaultStepSizeLighting         =  10.0f;
61 const float HdStVolume::defaultMaxTextureMemoryPerField = 128.0f;
62 
HdStVolume(SdfPath const & id)63 HdStVolume::HdStVolume(SdfPath const& id)
64     : HdVolume(id)
65 {
66 }
67 
68 HdStVolume::~HdStVolume() = default;
69 
70 // Dirty bits requiring recomputing the material shader and the
71 // bounding box.
72 static const int _shaderAndBBoxComputationDirtyBitsMask =
73     HdChangeTracker::Clean
74     | HdChangeTracker::DirtyExtent
75     | HdChangeTracker::DirtyMaterialId
76     | HdChangeTracker::DirtyRepr
77     | HdChangeTracker::DirtyVolumeField;
78 
79 static const int _initialDirtyBitsMask =
80     _shaderAndBBoxComputationDirtyBitsMask
81     | HdChangeTracker::DirtyPrimID
82     | HdChangeTracker::DirtyPrimvar
83     | HdChangeTracker::DirtyTransform
84     | HdChangeTracker::DirtyVisibility
85     | HdChangeTracker::DirtyInstancer;
86 
87 HdDirtyBits
GetInitialDirtyBitsMask() const88 HdStVolume::GetInitialDirtyBitsMask() const
89 {
90     int mask = _initialDirtyBitsMask;
91     return (HdDirtyBits)mask;
92 }
93 
94 HdDirtyBits
_PropagateDirtyBits(HdDirtyBits bits) const95 HdStVolume::_PropagateDirtyBits(HdDirtyBits bits) const
96 {
97     return bits;
98 }
99 
100 void
_InitRepr(TfToken const & reprToken,HdDirtyBits * dirtyBits)101 HdStVolume::_InitRepr(TfToken const &reprToken, HdDirtyBits* dirtyBits)
102 {
103     // All representations point to _volumeRepr.
104     if (!_volumeRepr) {
105         _volumeRepr = std::make_shared<HdRepr>();
106         _volumeRepr->AddDrawItem(
107             std::make_unique<HdStDrawItem>(&_sharedData));
108         *dirtyBits |= HdChangeTracker::NewRepr;
109     }
110 
111     _ReprVector::iterator it = std::find_if(_reprs.begin(), _reprs.end(),
112                                             _ReprComparator(reprToken));
113     bool isNew = it == _reprs.end();
114     if (isNew) {
115         // add new repr
116         it = _reprs.insert(_reprs.end(),
117                 std::make_pair(reprToken, _volumeRepr));
118     }
119 }
120 
121 void
Sync(HdSceneDelegate * delegate,HdRenderParam * renderParam,HdDirtyBits * dirtyBits,TfToken const & reprToken)122 HdStVolume::Sync(HdSceneDelegate *delegate,
123                  HdRenderParam   *renderParam,
124                  HdDirtyBits     *dirtyBits,
125                  TfToken const   &reprToken)
126 {
127     _UpdateVisibility(delegate, dirtyBits);
128 
129     if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
130         HdStSetMaterialId(delegate, renderParam, this);
131 
132         HdStDrawItem * const drawItem = static_cast<HdStDrawItem*>(
133             _volumeRepr->GetDrawItem(0));
134         HdStSetMaterialTag(renderParam, drawItem,
135             HdStMaterialTagTokens->volume);
136     }
137 
138     _UpdateRepr(delegate, renderParam, reprToken, dirtyBits);
139 
140     // This clears all the non-custom dirty bits. This ensures that the rprim
141     // doesn't have pending dirty bits that add it to the dirty list every
142     // frame.
143     // XXX: GetInitialDirtyBitsMask sets certain dirty bits that aren't
144     // reset (e.g. DirtyExtent, DirtyPrimID) that make this necessary.
145     *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits;
146 }
147 
148 void
Finalize(HdRenderParam * renderParam)149 HdStVolume::Finalize(HdRenderParam *renderParam)
150 {
151     HdStMarkGarbageCollectionNeeded(renderParam);
152 
153     HdStRenderParam * const stRenderParam =
154         static_cast<HdStRenderParam*>(renderParam);
155 
156     // Decrement material tag count for volume material tag
157     stRenderParam->DecreaseMaterialTagCount(HdStMaterialTagTokens->volume);
158 }
159 
160 void
_UpdateRepr(HdSceneDelegate * sceneDelegate,HdRenderParam * renderParam,TfToken const & reprToken,HdDirtyBits * dirtyBits)161 HdStVolume::_UpdateRepr(HdSceneDelegate *sceneDelegate,
162                         HdRenderParam *renderParam,
163                         TfToken const &reprToken,
164                         HdDirtyBits *dirtyBits)
165 {
166     HD_TRACE_FUNCTION();
167     HF_MALLOC_TAG_FUNCTION();
168 
169     HdReprSharedPtr const &curRepr = _volumeRepr;
170 
171     if (TfDebug::IsEnabled(HD_RPRIM_UPDATED)) {
172         HdChangeTracker::DumpDirtyBits(*dirtyBits);
173     }
174 
175     HdStDrawItem * const drawItem = static_cast<HdStDrawItem*>(
176         curRepr->GetDrawItem(0));
177 
178     if (HdChangeTracker::IsDirty(*dirtyBits)) {
179         _UpdateDrawItem(sceneDelegate, renderParam, drawItem, dirtyBits);
180     }
181 
182     *dirtyBits &= ~HdChangeTracker::NewRepr;
183 }
184 
185 namespace {
186 
187 // Fallback volume data created from shaders/fallbackVolume.glslfx
188 HdStMaterial::VolumeMaterialData
_MakeFallbackVolumeMaterialData()189 _MakeFallbackVolumeMaterialData()
190 {
191     const HioGlslfx glslfx(HdStPackageFallbackVolumeShader());
192 
193     return
194         {
195             glslfx.GetVolumeSource(),
196             {
197                 HdSt_MaterialParam(
198                     HdSt_MaterialParam::ParamTypeFieldRedirect,
199                     _fallbackShaderTokens->density,
200                     VtValue(0.0f),
201                     { _fallbackShaderTokens->density }),
202                 HdSt_MaterialParam(
203                     HdSt_MaterialParam::ParamTypeFieldRedirect,
204                     _fallbackShaderTokens->emission,
205                     VtValue(GfVec3f(0.0, 0.0, 0.0)),
206                     { _fallbackShaderTokens->emission })
207             }
208         };
209 }
210 
211 const
212 HdStMaterial::VolumeMaterialData &
_ComputeVolumeMaterialData(const HdStMaterial * const material)213 _ComputeVolumeMaterialData(const HdStMaterial * const material)
214 {
215     // Try to use volume material data from material.
216     if (material) {
217         const HdStMaterial::VolumeMaterialData &data =
218             material->GetVolumeMaterialData();
219         if (!data.source.empty()) {
220             return data;
221         }
222     }
223 
224     // Instantiate fallback volume shader only once
225     //
226     // Note that the default HdStMaterial provides a fallback surface
227     // shader and we need a volume shader, so we create the shader here
228     // ourselves.
229     static const HdStMaterial::VolumeMaterialData fallbackData =
230         _MakeFallbackVolumeMaterialData();
231     return fallbackData;
232 }
233 
234 // A map from name to HdStVolumeFieldDescriptor (identifying a
235 // field prim).
236 //
237 // Initialized from a volume prim identified by its path. In the usd world,
238 // this map is created by following the field:NAME relationships on the volume
239 // prim to the targeted field prims. The information identifiying the field
240 // prim is inserted under the key NAME.
241 //
242 class _NameToFieldDescriptor
243 {
244 public:
245     // Get information from scene delegate and create map.
246     //
247     // Issue validation error if relationship did not target a field prim.
248     //
_NameToFieldDescriptor(HdSceneDelegate * const sceneDelegate,const SdfPath & id)249     _NameToFieldDescriptor(
250         HdSceneDelegate * const sceneDelegate,
251         const SdfPath &id)
252       : _descriptors(sceneDelegate->GetVolumeFieldDescriptors(id))
253     {
254         for (const HdVolumeFieldDescriptor &desc : _descriptors) {
255             if (dynamic_cast<HdStField*>(
256                     sceneDelegate->GetRenderIndex().GetBprim(
257                         desc.fieldPrimType, desc.fieldId))) {
258 
259                 _nameToDescriptor.insert({desc.fieldName, &desc});
260 
261             } else {
262                 HF_VALIDATION_WARN(
263                     id,
264                     "Volume has field relationship to non-field prim %s.",
265                     desc.fieldId.GetText());
266             }
267         }
268     }
269 
270     // Get information identifiying field prim associated to given name.
271     //
272     // Returns nullptr if no such field prim. Lifetime of returned object
273     // is tied to _NameToFieldDescriptor.
274     //
275     const HdVolumeFieldDescriptor *
GetDescriptor(const TfToken & name) const276     GetDescriptor(const TfToken &name) const {
277         const auto it = _nameToDescriptor.find(name);
278         if (it == _nameToDescriptor.end()) {
279             return nullptr;
280         }
281         return it->second;
282     }
283 
284 private:
285     using _NameToDescriptor =
286         std::unordered_map<TfToken,
287                            const HdVolumeFieldDescriptor *,
288                            TfToken::HashFunctor>;
289     HdVolumeFieldDescriptorVector _descriptors;
290     _NameToDescriptor _nameToDescriptor;
291 };
292 
293 // Add GLSL code such as "HdGet_density(vec3 p)" for sampling the fields
294 // to the volume shader code and add necessary 3d textures and other
295 // parameters and buffer sources to the resulting HdSt_VolumeShader.
296 // HdMaterialParam's are consulted to figure out the names of the fields
297 // to sample and the names of the associated sampling functions to generate.
298 //
299 // The resulting shader can also fill the points bar of the volume computed
300 // from the bounding box of the volume.
301 //
302 HdSt_VolumeShaderSharedPtr
_ComputeMaterialNetworkShader(HdSceneDelegate * const sceneDelegate,const SdfPath & id,const HdStMaterial::VolumeMaterialData & volumeMaterialData,const GfRange3d & authoredExtents)303 _ComputeMaterialNetworkShader(
304     HdSceneDelegate * const sceneDelegate,
305     const SdfPath &id,
306     const HdStMaterial::VolumeMaterialData &volumeMaterialData,
307     const GfRange3d &authoredExtents)
308 {
309     TRACE_FUNCTION();
310 
311     HdStResourceRegistrySharedPtr const resourceRegistry =
312         std::static_pointer_cast<HdStResourceRegistry>(
313             sceneDelegate->GetRenderIndex().GetResourceRegistry());
314 
315     // Generate new shader from volume shader
316     HdSt_VolumeShaderSharedPtr const result =
317         std::make_shared<HdSt_VolumeShader>(
318             sceneDelegate->GetRenderIndex().GetRenderDelegate());
319 
320     // Buffer specs and source for the shader BAR
321     HdBufferSpecVector bufferSpecs;
322     HdBufferSourceSharedPtrVector bufferSources;
323 
324     // The names of the fields read by field readers.
325     std::set<TfToken> fieldNames;
326 
327     for (const auto & param : volumeMaterialData.params) {
328         // Scan original parameters...
329         if ( param.IsFieldRedirect() ||
330              param.IsPrimvarRedirect() ||
331              param.IsFallback() ) {
332             // Add fallback values for parameters
333             HdSt_MaterialNetworkShader::AddFallbackValueToSpecsAndSources(
334                 param, &bufferSpecs, &bufferSources);
335 
336             if (param.IsFieldRedirect()) {
337                 // Determine the name of the field the field reader requests.
338                 TfTokenVector const &names = param.samplerCoords;
339                 if (!names.empty()) {
340                     fieldNames.insert(names[0]);
341                 }
342             }
343         }
344         // Ignoring 2D texture parameters for volumes.
345     }
346 
347     // Make a copy of the original params
348     HdSt_MaterialParamVector params = volumeMaterialData.params;
349 
350     // Note that it is a requirement of HdSt_VolumeShader that
351     // namedTextureHandles and fieldDescs line up.
352     HdStShaderCode::NamedTextureHandleVector namedTextureHandles;
353     HdVolumeFieldDescriptorVector fieldDescs;
354 
355     const _NameToFieldDescriptor _nameToFieldDescriptor(sceneDelegate, id);
356 
357     // For each requested field name, record the information needed to
358     // allocate the necessary texture later:
359     // - a texture HdSt_MaterialParam
360     // - an HdVolumeFieldDescriptor identifying the HdStField prim holding
361     //   the path to the texture
362     // - a HdStShader::NamedTextureHandle initialized with a null-handle.
363     //
364     for (const auto & fieldName : fieldNames) {
365         // See whether we have the the field in the volume field
366         // descriptors given to us by the scene delegate.
367         const HdVolumeFieldDescriptor * const desc =
368             _nameToFieldDescriptor.GetDescriptor(fieldName);
369         if (!desc) {
370             // Invalid field prim, skip.
371             continue;
372         }
373 
374         // Record field descriptor
375         fieldDescs.push_back(*desc);
376 
377         const TfToken textureName(
378             fieldName.GetString() +
379             HdSt_ResourceBindingSuffixTokens->texture.GetString());
380         static const HdTextureType textureType = HdTextureType::Field;
381 
382         // Produce HdGet_FIELDNAME_texture(vec3 p) to sample
383         // the texture.
384         const HdSt_MaterialParam param(
385             HdSt_MaterialParam::ParamTypeTexture,
386             textureName,
387             VtValue(GfVec4f(0)),
388             TfTokenVector(),
389             textureType);
390 
391         HdSt_MaterialNetworkShader::AddFallbackValueToSpecsAndSources(
392             param, &bufferSpecs, &bufferSources);
393 
394         params.push_back(param);
395 
396         namedTextureHandles.push_back(
397             { textureName, textureType, nullptr, desc->fieldId.GetHash() });
398     }
399 
400     // Get buffer specs for textures (i.e., for
401     // field sampling transforms and bindless texture handles).
402     HdSt_TextureBinder::GetBufferSpecs(namedTextureHandles, &bufferSpecs);
403 
404     // Create params (so that HdGet_... are created) and buffer specs,
405     // to communicate volume bounding box and sample distance to shader.
406     HdSt_VolumeShader::GetParamsAndBufferSpecsForBBoxAndSampleDistance(
407         &params, &bufferSpecs);
408 
409     const bool hasField = !namedTextureHandles.empty();
410 
411     // If there is a field, we postpone giving buffer sources for
412     // the volume bounding box until after the textures have been
413     // committed.
414     if (!hasField) {
415         HdSt_VolumeShader::GetBufferSourcesForBBoxAndSampleDistance(
416             { GfBBox3d(authoredExtents), 1.0f },
417             &bufferSources);
418     }
419 
420     // Make volume shader responsible if we have fields with bounding
421     // boxes.
422     result->SetFillsPointsBar(hasField);
423     result->SetParams(params);
424     result->SetBufferSources(
425         bufferSpecs, std::move(bufferSources), resourceRegistry);
426     result->SetNamedTextureHandles(namedTextureHandles);
427     result->SetFieldDescriptors(fieldDescs);
428 
429     // Append the volume shader (calling into the GLSL functions
430     // generated above)
431     result->SetFragmentSource(volumeMaterialData.source);
432 
433     return result;
434 }
435 
436 VtValue
_ComputeBBoxVertices(GfRange3d const & range)437 _ComputeBBoxVertices(GfRange3d const &range)
438 {
439     VtVec3fArray result(8);
440 
441     const GfVec3d min = HdSt_VolumeShader::GetSafeMin(range);
442     const GfVec3d max = HdSt_VolumeShader::GetSafeMax(range);
443 
444     int i = 0;
445 
446     for (const double x : { min[0], max[0] }) {
447         for (const double y : { min[1], max[1] }) {
448             for (const double z : { min[2], max[2] }) {
449                 result[i] = GfVec3f(x,y,z);
450                 i++;
451             }
452         }
453     }
454 
455     return VtValue(result);
456 }
457 
458 const VtValue &
_GetCubeTriangleIndices()459 _GetCubeTriangleIndices()
460 {
461     static const VtValue result(
462         VtVec3iArray{
463                 GfVec3i(1,3,2),
464                 GfVec3i(0,1,2),
465 
466                 GfVec3i(7,5,4),
467                 GfVec3i(6,7,4),
468 
469                 GfVec3i(5,1,0),
470                 GfVec3i(4,5,0),
471 
472                 GfVec3i(3,7,6),
473                 GfVec3i(2,3,6),
474 
475                 GfVec3i(2,6,4),
476                 GfVec3i(0,2,4),
477 
478                 GfVec3i(7,3,1),
479                 GfVec3i(5,7,1)});
480 
481     return result;
482 }
483 
484 } // end namespace
485 
486 void
_UpdateDrawItem(HdSceneDelegate * sceneDelegate,HdRenderParam * renderParam,HdStDrawItem * drawItem,HdDirtyBits * dirtyBits)487 HdStVolume::_UpdateDrawItem(HdSceneDelegate *sceneDelegate,
488                             HdRenderParam *renderParam,
489                             HdStDrawItem *drawItem,
490                             HdDirtyBits *dirtyBits)
491 {
492     HD_TRACE_FUNCTION();
493     HF_MALLOC_TAG_FUNCTION();
494 
495     if (HdStShouldPopulateConstantPrimvars(dirtyBits, GetId())) {
496         /* CONSTANT PRIMVARS, TRANSFORM AND EXTENT */
497         const HdPrimvarDescriptorVector constantPrimvars =
498             HdStGetPrimvarDescriptors(this, drawItem, sceneDelegate,
499                                       HdInterpolationConstant);
500         HdStPopulateConstantPrimvars(this,
501                                      &_sharedData,
502                                      sceneDelegate,
503                                      renderParam,
504                                      drawItem,
505                                      dirtyBits,
506                                      constantPrimvars);
507     }
508 
509     if ((*dirtyBits) & HdChangeTracker::DirtyMaterialId) {
510         /* MATERIAL SHADER (may affect subsequent primvar population) */
511 
512         // Note that the creation of the HdSt_VolumeShader and the
513         // allocation of the necessary textures is driven by two
514         // different dirtyBits (HdChangeTracker::DirtyMaterialId and
515         // HdChangeTracker::DirtyVolumeField).
516         //
517         // This way, we do not need to re-create the shader on every frame
518         // when the fields of a volume are animated.
519         //
520         const HdStMaterial * const material = static_cast<const HdStMaterial *>(
521             sceneDelegate->GetRenderIndex().GetSprim(
522                 HdPrimTypeTokens->material, GetMaterialId()));
523 
524         // Compute the material shader by adding GLSL code such as
525         // "HdGet_density(vec3 p)" for sampling the fields needed by the volume
526         // shader.
527         // The material shader will eventually be concatenated with
528         // the geometry shader which does the raymarching and is calling into
529         // GLSL functions such as "float scattering(vec3)" in the volume shader
530         // to evaluate physical properties of a volume at the point p.
531 
532         drawItem->SetMaterialNetworkShader(
533             _ComputeMaterialNetworkShader(
534                 sceneDelegate,
535                 GetId(),
536                 _ComputeVolumeMaterialData(material),
537                 _sharedData.bounds.GetRange()));
538     }
539 
540     HdStResourceRegistrySharedPtr resourceRegistry =
541         std::static_pointer_cast<HdStResourceRegistry>(
542             sceneDelegate->GetRenderIndex().GetResourceRegistry());
543 
544     HdSt_VolumeShaderSharedPtr const materialNetworkShader =
545         std::dynamic_pointer_cast<HdSt_VolumeShader>(
546             drawItem->GetMaterialNetworkShader());
547 
548     if (!materialNetworkShader) {
549         TF_CODING_ERROR("Expected valid volume shader for draw item.");
550         return;
551     }
552 
553     if ((*dirtyBits) & (HdChangeTracker::DirtyVolumeField |
554                         HdChangeTracker::DirtyMaterialId)) {
555         /* FIELD TEXTURES */
556 
557         // (Re-)Allocate the textures associated with the field prims.
558         materialNetworkShader->UpdateTextureHandles(sceneDelegate);
559     }
560 
561     /* VERTICES */
562     if ((*dirtyBits) & _shaderAndBBoxComputationDirtyBitsMask) {
563         // Any change to the bounding box requires us to recompute
564         // the vertices
565         //
566         if (!HdStIsValidBAR(drawItem->GetVertexPrimvarRange())) {
567             static const HdBufferSpecVector bufferSpecs{
568                 HdBufferSpec(HdTokens->points,
569                              HdTupleType{ HdTypeFloatVec3, 1 })
570             };
571 
572             HdBufferArrayRangeSharedPtr const range =
573                 resourceRegistry->AllocateNonUniformBufferArrayRange(
574                     HdTokens->primvar, bufferSpecs, HdBufferArrayUsageHint());
575             _sharedData.barContainer.Set(
576                 drawItem->GetDrawingCoord()->GetVertexPrimvarIndex(), range);
577         }
578 
579         // Let HdSt_VolumeShader know about the points bar so that it
580         // can fill it with the vertices of the volume bounding box.
581         materialNetworkShader->SetPointsBar(drawItem->GetVertexPrimvarRange());
582 
583         // If HdSt_VolumeShader is not in charge of filling the points bar
584         // from the volume bounding box computed from the fields, ...
585         if (!materialNetworkShader->GetFillsPointsBar()) {
586             // ... fill the points from the authored extents.
587             resourceRegistry->AddSource(
588                 drawItem->GetVertexPrimvarRange(),
589                 std::make_shared<HdVtBufferSource>(
590                     HdTokens->points,
591                     _ComputeBBoxVertices(
592                         _sharedData.bounds.GetRange())));
593         }
594     }
595 
596     if ((*dirtyBits) & HdChangeTracker::NewRepr) {
597         // Bounding box topology and geometric shader key only need to
598         // be initialized the first time we make the draw item.
599 
600         const HdSt_VolumeShaderKey shaderKey;
601         drawItem->SetGeometricShader(
602             HdSt_GeometricShader::Create(shaderKey, resourceRegistry));
603 
604         /* TRIANGLE INDICES */
605         {
606             // XXX:
607             // Always the same triangle indices, should they be allocated only
608             // once and shared across all volumes?
609             HdBufferSourceSharedPtr const source =
610                 std::make_shared<HdVtBufferSource>(
611                     HdTokens->indices, _GetCubeTriangleIndices());
612 
613             HdBufferSourceSharedPtrVector sources = { source };
614 
615             if (!HdStIsValidBAR(drawItem->GetTopologyRange())) {
616                 HdBufferSpecVector bufferSpecs;
617                 HdBufferSpec::GetBufferSpecs(sources, &bufferSpecs);
618 
619                 HdBufferArrayRangeSharedPtr const range =
620                     resourceRegistry->AllocateNonUniformBufferArrayRange(
621                         HdTokens->primvar, bufferSpecs,
622                         HdBufferArrayUsageHint());
623                 _sharedData.barContainer.Set(
624                     drawItem->GetDrawingCoord()->GetTopologyIndex(), range);
625             }
626 
627             resourceRegistry->AddSources(drawItem->GetTopologyRange(),
628                                          std::move(sources));
629         }
630     }
631 }
632 
633 PXR_NAMESPACE_CLOSE_SCOPE
634