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/glf/contextCaps.h"
25 
26 #include "pxr/imaging/hdSt/interleavedMemoryManager.h"
27 #include "pxr/imaging/hdSt/bufferResource.h"
28 #include "pxr/imaging/hdSt/glUtils.h"
29 #include "pxr/imaging/hdSt/resourceRegistry.h"
30 #include "pxr/imaging/hdSt/stagingBuffer.h"
31 #include "pxr/imaging/hdSt/tokens.h"
32 
33 #include "pxr/imaging/hgi/hgi.h"
34 #include "pxr/imaging/hgi/blitCmds.h"
35 #include "pxr/imaging/hgi/blitCmdsOps.h"
36 #include "pxr/imaging/hgi/buffer.h"
37 
38 #include "pxr/base/arch/hash.h"
39 #include "pxr/base/tf/diagnostic.h"
40 #include "pxr/base/tf/enum.h"
41 #include "pxr/base/tf/iterator.h"
42 
43 #include "pxr/imaging/hd/perfLog.h"
44 #include "pxr/imaging/hd/tokens.h"
45 
46 #include "pxr/imaging/hf/perfLog.h"
47 
48 #include <vector>
49 
50 PXR_NAMESPACE_OPEN_SCOPE
51 
52 // ---------------------------------------------------------------------------
53 //  HdStInterleavedMemoryManager
54 // ---------------------------------------------------------------------------
55 HdBufferArrayRangeSharedPtr
CreateBufferArrayRange()56 HdStInterleavedMemoryManager::CreateBufferArrayRange()
57 {
58     return std::make_shared<_StripedInterleavedBufferRange>(_resourceRegistry);
59 }
60 
61 /// Returns the buffer specs from a given buffer array
62 HdBufferSpecVector
GetBufferSpecs(HdBufferArraySharedPtr const & bufferArray) const63 HdStInterleavedMemoryManager::GetBufferSpecs(
64     HdBufferArraySharedPtr const &bufferArray) const
65 {
66     _StripedInterleavedBufferSharedPtr bufferArray_ =
67         std::static_pointer_cast<_StripedInterleavedBuffer> (bufferArray);
68     return bufferArray_->GetBufferSpecs();
69 }
70 
71 /// Returns the size of the GPU memory used by the passed buffer array
72 size_t
GetResourceAllocation(HdBufferArraySharedPtr const & bufferArray,VtDictionary & result) const73 HdStInterleavedMemoryManager::GetResourceAllocation(
74     HdBufferArraySharedPtr const &bufferArray,
75     VtDictionary &result) const
76 {
77     std::set<uint64_t> idSet;
78     size_t gpuMemoryUsed = 0;
79 
80     _StripedInterleavedBufferSharedPtr bufferArray_ =
81         std::static_pointer_cast<_StripedInterleavedBuffer> (bufferArray);
82 
83     TF_FOR_ALL(resIt, bufferArray_->GetResources()) {
84         HdStBufferResourceSharedPtr const & resource = resIt->second;
85 
86         HgiBufferHandle buffer = resource->GetHandle();
87 
88         // XXX avoid double counting of resources shared within a buffer
89         uint64_t id = buffer ? buffer->GetRawResource() : 0;
90         if (idSet.count(id) == 0) {
91             idSet.insert(id);
92 
93             std::string const & role = resource->GetRole().GetString();
94             size_t size = size_t(resource->GetSize());
95 
96             if (result.count(role)) {
97                 size_t currentSize = result[role].Get<size_t>();
98                 result[role] = VtValue(currentSize + size);
99             } else {
100                 result[role] = VtValue(size);
101             }
102 
103             gpuMemoryUsed += size;
104         }
105     }
106 
107     return gpuMemoryUsed;
108 }
109 
110 // ---------------------------------------------------------------------------
111 //  HdStInterleavedUBOMemoryManager
112 // ---------------------------------------------------------------------------
113 HdBufferArraySharedPtr
CreateBufferArray(TfToken const & role,HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint)114 HdStInterleavedUBOMemoryManager::CreateBufferArray(
115     TfToken const &role,
116     HdBufferSpecVector const &bufferSpecs,
117     HdBufferArrayUsageHint usageHint)
118 {
119     const GlfContextCaps &caps = GlfContextCaps::GetInstance();
120 
121     return std::make_shared<
122         HdStInterleavedMemoryManager::_StripedInterleavedBuffer>(
123             this,
124             _resourceRegistry,
125             role,
126             bufferSpecs,
127             usageHint,
128             caps.uniformBufferOffsetAlignment,
129             /*structAlignment=*/sizeof(float)*4,
130             caps.maxUniformBlockSize,
131             HdPerfTokens->garbageCollectedUbo);
132 }
133 
134 HdAggregationStrategy::AggregationId
ComputeAggregationId(HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint) const135 HdStInterleavedUBOMemoryManager::ComputeAggregationId(
136     HdBufferSpecVector const &bufferSpecs,
137     HdBufferArrayUsageHint usageHint) const
138 {
139     static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__));
140     size_t result = salt;
141     for (HdBufferSpec const &spec : bufferSpecs) {
142         boost::hash_combine(result, spec.Hash());
143     }
144     boost::hash_combine(result, usageHint.value);
145 
146     // promote to size_t
147     return (AggregationId)result;
148 }
149 
150 // ---------------------------------------------------------------------------
151 //  HdStInterleavedSSBOMemoryManager
152 // ---------------------------------------------------------------------------
153 HdBufferArraySharedPtr
CreateBufferArray(TfToken const & role,HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint)154 HdStInterleavedSSBOMemoryManager::CreateBufferArray(
155     TfToken const &role,
156     HdBufferSpecVector const &bufferSpecs,
157     HdBufferArrayUsageHint usageHint)
158 {
159     const GlfContextCaps &caps = GlfContextCaps::GetInstance();
160 
161     return std::make_shared<
162         HdStInterleavedMemoryManager::_StripedInterleavedBuffer>(
163             this,
164             _resourceRegistry,
165             role,
166             bufferSpecs,
167             usageHint,
168             /*bufferOffsetAlignment=*/0,
169             /*structAlignment=*/0,
170             caps.maxShaderStorageBlockSize,
171             HdPerfTokens->garbageCollectedSsbo);
172 }
173 
174 HdAggregationStrategy::AggregationId
ComputeAggregationId(HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint) const175 HdStInterleavedSSBOMemoryManager::ComputeAggregationId(
176     HdBufferSpecVector const &bufferSpecs,
177     HdBufferArrayUsageHint usageHint) const
178 {
179     static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__));
180     size_t result = salt;
181     for (HdBufferSpec const &spec : bufferSpecs) {
182         boost::hash_combine(result, spec.Hash());
183     }
184     boost::hash_combine(result, usageHint.value);
185 
186     return result;
187 }
188 
189 // ---------------------------------------------------------------------------
190 //  _StripedInterleavedBuffer
191 // ---------------------------------------------------------------------------
192 
193 static inline int
_ComputePadding(int alignment,int currentOffset)194 _ComputePadding(int alignment, int currentOffset)
195 {
196     return ((alignment - (currentOffset & (alignment - 1))) & (alignment - 1));
197 }
198 
199 static inline int
_ComputeAlignment(HdTupleType tupleType)200 _ComputeAlignment(HdTupleType tupleType)
201 {
202     const HdType componentType = HdGetComponentType(tupleType.type);
203     const int numComponents = HdGetComponentCount(tupleType.type);
204     const int componentSize = HdDataSizeOfType(componentType);
205 
206     // This is simplified to treat arrays of int and floats
207     // as vectors. The padding rules state that if we have
208     // an array of 2 ints, it would get aligned to the size
209     // of a vec4, where as a vec2 of ints or floats is aligned
210     // to the size of a vec2. Since we don't know if something is
211     // an array or vector, we are treating them as vectors.
212     //
213     // XXX:Arrays: Now that we do know whether a value is an array
214     // or vector, we can update this to do the right thing.
215 
216     // Matrices are treated as an array of vec4s, so the
217     // max num components we are looking at is 4
218     int alignComponents = std::min(numComponents, 4);
219 
220     // single elements and vec2's are allowed, but
221     // vec3's get rounded up to vec4's
222     if(alignComponents == 3) {
223         alignComponents = 4;
224     }
225 
226     return componentSize * alignComponents;
227 }
228 
_StripedInterleavedBuffer(HdStInterleavedMemoryManager * mgr,HdStResourceRegistry * resourceRegistry,TfToken const & role,HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint,int bufferOffsetAlignment=0,int structAlignment=0,size_t maxSize=0,TfToken const & garbageCollectionPerfToken=HdPerfTokens->garbageCollectedUbo)229 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_StripedInterleavedBuffer(
230     HdStInterleavedMemoryManager* mgr,
231     HdStResourceRegistry* resourceRegistry,
232     TfToken const &role,
233     HdBufferSpecVector const &bufferSpecs,
234     HdBufferArrayUsageHint usageHint,
235     int bufferOffsetAlignment = 0,
236     int structAlignment = 0,
237     size_t maxSize = 0,
238     TfToken const &garbageCollectionPerfToken = HdPerfTokens->garbageCollectedUbo)
239     : HdBufferArray(role, garbageCollectionPerfToken, usageHint),
240       _manager(mgr),
241       _resourceRegistry(resourceRegistry),
242       _needsCompaction(false),
243       _stride(0),
244       _bufferOffsetAlignment(bufferOffsetAlignment),
245       _maxSize(maxSize)
246 
247 {
248     HD_TRACE_FUNCTION();
249     HF_MALLOC_TAG_FUNCTION();
250 
251     /*
252        interleaved uniform buffer layout (for example)
253 
254                 .--range["color"].offset
255                 v
256       .--------------------------------------------------.
257       | Xf      : Color      || Xf       : Color   || ...|
258       '--------------------------------------------------'
259        ^------- stride ------^
260        ^---- one element ----^
261     */
262 
263     /*
264      do std140/std430 packing (GL spec section 7.6.2.2)
265       When using the "std430" storage layout, shader storage
266       blocks will be laid out in buffer storage identically to uniform and
267       shader storage blocks using the "std140" layout, except that the base
268       alignment of arrays of scalars and vectors in rule (4) and of structures
269       in rule (9) are not rounded up a multiple of the base alignment of a vec4.
270      */
271 
272     TF_FOR_ALL(it, bufferSpecs) {
273         // Figure out the alignment we need for this type of data
274         int alignment = _ComputeAlignment(it->tupleType);
275         _stride += _ComputePadding(alignment, _stride);
276 
277         // We need to save the max alignment size for later because the
278         // stride for our struct needs to be aligned to this
279         structAlignment = std::max(structAlignment, alignment);
280 
281         _stride += HdDataSizeOfTupleType(it->tupleType);
282     }
283 
284     // Our struct stride needs to be aligned to the max alignment needed within
285     // our struct.
286     _stride += _ComputePadding(structAlignment, _stride);
287 
288     // and also aligned if bufferOffsetAlignment exists (for UBO binding)
289     if (_bufferOffsetAlignment > 0) {
290         _stride += _ComputePadding(_bufferOffsetAlignment, _stride);
291     }
292 
293     TF_VERIFY(_stride > 0);
294 
295     TF_DEBUG_MSG(HD_BUFFER_ARRAY_INFO,
296                  "Create interleaved buffer array: stride = %d\n", _stride);
297 
298     // populate BufferResources, interleaved
299     int offset = 0;
300     TF_FOR_ALL(it, bufferSpecs) {
301         // Figure out alignment for this data member
302         int alignment = _ComputeAlignment(it->tupleType);
303         // Add any needed padding to fixup alignment
304         offset += _ComputePadding(alignment, offset);
305 
306         _AddResource(it->name, it->tupleType, offset, _stride);
307 
308         TF_DEBUG_MSG(HD_BUFFER_ARRAY_INFO,
309                      "  %s : offset = %d, alignment = %d\n",
310                      it->name.GetText(), offset, alignment);
311 
312         offset += HdDataSizeOfTupleType(it->tupleType);
313     }
314 
315     _SetMaxNumRanges(_maxSize / _stride);
316 
317     TF_VERIFY(_stride + offset);
318 }
319 
320 HdStBufferResourceSharedPtr
_AddResource(TfToken const & name,HdTupleType tupleType,int offset,int stride)321 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_AddResource(
322     TfToken const& name,
323     HdTupleType tupleType,
324     int offset,
325     int stride)
326 {
327     HD_TRACE_FUNCTION();
328 
329     if (TfDebug::IsEnabled(HD_SAFE_MODE)) {
330         // duplication check
331         HdStBufferResourceSharedPtr bufferRes = GetResource(name);
332         if (!TF_VERIFY(!bufferRes)) {
333             return bufferRes;
334         }
335     }
336 
337     HdStBufferResourceSharedPtr bufferRes = std::make_shared<HdStBufferResource>
338         (GetRole(), tupleType, offset, stride);
339 
340     _resourceList.emplace_back(name, bufferRes);
341     return bufferRes;
342 }
343 
344 
~_StripedInterleavedBuffer()345 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::~_StripedInterleavedBuffer()
346 {
347     HD_TRACE_FUNCTION();
348     HF_MALLOC_TAG_FUNCTION();
349 
350     // invalidate buffer array ranges in range list
351     // (these ranges may still be held by drawItems)
352     size_t rangeCount = GetRangeCount();
353     for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
354         _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx);
355 
356         if (range)
357         {
358             range->Invalidate();
359         }
360     }
361 }
362 
363 bool
GarbageCollect()364 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GarbageCollect()
365 {
366     HD_TRACE_FUNCTION();
367     HF_MALLOC_TAG_FUNCTION();
368 
369     if (_needsCompaction) {
370         RemoveUnusedRanges();
371 
372         std::vector<HdBufferArrayRangeSharedPtr> ranges;
373         size_t rangeCount = GetRangeCount();
374         ranges.reserve(rangeCount);
375         for (size_t i = 0; i < rangeCount; ++i) {
376             HdBufferArrayRangeSharedPtr range = GetRange(i).lock();
377             if (range)
378                 ranges.push_back(range);
379         }
380         Reallocate(ranges, shared_from_this());
381     }
382 
383     if (GetRangeCount() == 0) {
384         _DeallocateResources();
385         return true;
386     }
387 
388     return false;
389 }
390 
391 void
Reallocate(std::vector<HdBufferArrayRangeSharedPtr> const & ranges,HdBufferArraySharedPtr const & curRangeOwner)392 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::Reallocate(
393     std::vector<HdBufferArrayRangeSharedPtr> const &ranges,
394     HdBufferArraySharedPtr const &curRangeOwner)
395 {
396     HD_TRACE_FUNCTION();
397     HF_MALLOC_TAG_FUNCTION();
398 
399     HgiBlitCmds* blitCmds = _resourceRegistry->GetGlobalBlitCmds();
400     blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__);
401 
402     HD_PERF_COUNTER_INCR(HdPerfTokens->vboRelocated);
403 
404     // Calculate element count
405     size_t elementCount = 0;
406     TF_FOR_ALL (it, ranges) {
407         HdBufferArrayRangeSharedPtr const &range = *it;
408         if (!range) {
409             TF_CODING_ERROR("Expired range found in the reallocation list");
410         }
411         elementCount += (*it)->GetNumElements();
412     }
413     size_t totalSize = elementCount * _stride;
414 
415     // update range list (should be done before early exit)
416     _SetRangeList(ranges);
417 
418     // resize each BufferResource
419     // all HdBufferSources are sharing same VBO
420 
421     // allocate new one
422     // curBuf and oldBuf will be different when we are adopting ranges
423     // from another buffer array.
424     HgiBufferHandle& oldBuf = GetResources().begin()->second->GetHandle();
425 
426     _StripedInterleavedBufferSharedPtr curRangeOwner_ =
427         std::static_pointer_cast<_StripedInterleavedBuffer> (curRangeOwner);
428 
429     HgiBufferHandle const& curBuf =
430         curRangeOwner_->GetResources().begin()->second->GetHandle();
431     HgiBufferHandle newBuf;
432 
433     Hgi* hgi = _resourceRegistry->GetHgi();
434 
435     // Skip buffers of zero size.
436     if (totalSize > 0) {
437         HgiBufferDesc bufDesc;
438         bufDesc.byteSize = totalSize;
439         bufDesc.usage = HgiBufferUsageUniform;
440         newBuf = hgi->CreateBuffer(bufDesc);
441     }
442 
443     // if old and new buffer exist, copy unchanged data
444     if (curBuf && newBuf) {
445         int index = 0;
446 
447         size_t rangeCount = GetRangeCount();
448 
449         // pre-pass to combine consecutive buffer range relocation
450         HdStBufferRelocator relocator(curBuf, newBuf);
451         for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
452             _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx);
453 
454             if (!range) {
455                 TF_CODING_ERROR("_StripedInterleavedBufferRange expired "
456                                 "unexpectedly.");
457                 continue;
458             }
459             int oldIndex = range->GetElementOffset();
460             if (oldIndex >= 0) {
461                 // copy old data
462                 ptrdiff_t readOffset = oldIndex * _stride;
463                 ptrdiff_t writeOffset = index * _stride;
464                 ptrdiff_t copySize = _stride * range->GetNumElements();
465 
466                 relocator.AddRange(readOffset, writeOffset, copySize);
467             }
468 
469             range->SetIndex(index);
470             index += range->GetNumElements();
471         }
472 
473         // buffer copy
474         relocator.Commit(blitCmds);
475 
476     } else {
477         // just set index
478         int index = 0;
479 
480         size_t rangeCount = GetRangeCount();
481         for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
482             _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx);
483             if (!range) {
484                 TF_CODING_ERROR("_StripedInterleavedBufferRange expired "
485                                 "unexpectedly.");
486                 continue;
487             }
488 
489             range->SetIndex(index);
490             index += range->GetNumElements();
491         }
492     }
493     if (oldBuf) {
494         // delete old buffer
495         hgi->DestroyBuffer(&oldBuf);
496     }
497 
498     // update allocation to all buffer resources
499     TF_FOR_ALL(it, GetResources()) {
500         it->second->SetAllocation(newBuf, totalSize);
501     }
502 
503     blitCmds->PopDebugGroup();
504 
505     _needsReallocation = false;
506     _needsCompaction = false;
507 
508     // increment version to rebuild dispatch buffers.
509     IncrementVersion();
510 }
511 
512 void
_DeallocateResources()513 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::_DeallocateResources()
514 {
515     HdStBufferResourceSharedPtr resource = GetResource();
516     if (resource) {
517         _resourceRegistry->GetHgi()->DestroyBuffer(&resource->GetHandle());
518     }
519 }
520 
521 void
DebugDump(std::ostream & out) const522 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::DebugDump(std::ostream &out) const
523 {
524     out << "  HdStInterleavedMemoryManager\n";
525     out << "    Range entries " << GetRangeCount() << ":\n";
526 
527     size_t rangeCount = GetRangeCount();
528     for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
529         _StripedInterleavedBufferRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx);
530 
531         if (range) {
532             out << "      " << rangeIdx << *range;
533         }
534     }
535 }
536 
537 HdStBufferResourceSharedPtr
GetResource() const538 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetResource() const
539 {
540     HD_TRACE_FUNCTION();
541 
542     if (_resourceList.empty()) return HdStBufferResourceSharedPtr();
543 
544     if (TfDebug::IsEnabled(HD_SAFE_MODE)) {
545         // make sure this buffer array has only one resource.
546         HgiBufferHandle const& buffer =
547                 _resourceList.begin()->second->GetHandle();
548         TF_FOR_ALL (it, _resourceList) {
549             if (it->second->GetHandle() != buffer) {
550                 TF_CODING_ERROR("GetResource(void) called on"
551                                 "HdBufferArray having multiple GL resources");
552             }
553         }
554     }
555 
556     // returns the first item
557     return _resourceList.begin()->second;
558 }
559 
560 HdStBufferResourceSharedPtr
GetResource(TfToken const & name)561 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetResource(TfToken const& name)
562 {
563     HD_TRACE_FUNCTION();
564 
565     // linear search.
566     // The number of buffer resources should be small (<10 or so).
567     for (HdStBufferResourceNamedList::iterator it = _resourceList.begin();
568          it != _resourceList.end(); ++it) {
569         if (it->first == name) return it->second;
570     }
571     return HdStBufferResourceSharedPtr();
572 }
573 
574 HdBufferSpecVector
GetBufferSpecs() const575 HdStInterleavedMemoryManager::_StripedInterleavedBuffer::GetBufferSpecs() const
576 {
577     HdBufferSpecVector result;
578     result.reserve(_resourceList.size());
579     TF_FOR_ALL (it, _resourceList) {
580         result.emplace_back(it->first, it->second->GetTupleType());
581     }
582     return result;
583 }
584 
585 // ---------------------------------------------------------------------------
586 //  _StripedInterleavedBufferRange
587 // ---------------------------------------------------------------------------
~_StripedInterleavedBufferRange()588 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::~_StripedInterleavedBufferRange()
589 {
590     // Notify that hosting buffer array needs to be garbage collected.
591     //
592     // Don't do any substantial work here.
593     //
594     if (_stripedBuffer) {
595         _stripedBuffer->SetNeedsCompaction();
596     }
597 }
598 
599 
600 bool
IsAssigned() const601 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::IsAssigned() const
602 {
603     return (_stripedBuffer != nullptr);
604 }
605 
606 bool
IsImmutable() const607 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::IsImmutable() const
608 {
609     return (_stripedBuffer != nullptr)
610          && _stripedBuffer->IsImmutable();
611 }
612 
613 bool
RequiresStaging() const614 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::RequiresStaging() const
615 {
616     return true;
617 }
618 
619 bool
Resize(int numElements)620 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::Resize(int numElements)
621 {
622     HD_TRACE_FUNCTION();
623     HF_MALLOC_TAG_FUNCTION();
624 
625     if (!TF_VERIFY(_stripedBuffer)) return false;
626 
627     // interleaved BAR never needs to be resized, since numElements in buffer
628     // resources is always 1. Note that the arg numElements of this function
629     // could be more than 1 for static array.
630     // ignore Resize request.
631 
632     // XXX: this could be a problem if a client allows to change the array size
633     //      dynamically -- e.g. instancer nesting level changes.
634     //
635     return false;
636 }
637 
638 void
CopyData(HdBufferSourceSharedPtr const & bufferSource)639 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::CopyData(
640     HdBufferSourceSharedPtr const &bufferSource)
641 {
642     HD_TRACE_FUNCTION();
643     HF_MALLOC_TAG_FUNCTION();
644 
645     if (!TF_VERIFY(_stripedBuffer)) return;
646 
647     HdStBufferResourceSharedPtr VBO =
648         _stripedBuffer->GetResource(bufferSource->GetName());
649 
650     if (!VBO || !VBO->GetHandle()) {
651         TF_CODING_ERROR("VBO doesn't exist for %s",
652                         bufferSource->GetName().GetText());
653         return;
654     }
655 
656     // overrun check
657     // XXX:Arrays:  Note that we only check tuple type here, not arity.
658     // This code allows N-tuples and N-element arrays to be interchanged.
659     // It would seem better to have upstream buffers adjust their tuple
660     // arity as needed.
661     if (!TF_VERIFY(
662         bufferSource->GetTupleType().type == VBO->GetTupleType().type,
663         "'%s': (%s (%i) x %zu) != (%s (%i) x %zu)\n",
664         bufferSource->GetName().GetText(),
665         TfEnum::GetName(bufferSource->GetTupleType().type).c_str(),
666         bufferSource->GetTupleType().type,
667         bufferSource->GetTupleType().count,
668         TfEnum::GetName(VBO->GetTupleType().type).c_str(),
669         VBO->GetTupleType().type,
670         VBO->GetTupleType().count)) {
671         return;
672     }
673 
674     int vboStride = VBO->GetStride();
675     size_t vboOffset = VBO->GetOffset() + vboStride * _index;
676     int dataSize = HdDataSizeOfTupleType(VBO->GetTupleType());
677 
678     const unsigned char *data =
679         (const unsigned char*)bufferSource->GetData();
680 
681     HgiBufferCpuToGpuOp blitOp;
682     blitOp.gpuDestinationBuffer = VBO->GetHandle();
683     blitOp.sourceByteOffset = 0;
684     blitOp.byteSize = dataSize;
685 
686     HdStStagingBuffer *stagingBuffer =
687         GetResourceRegistry()->GetStagingBuffer();
688 
689     for (size_t i = 0; i < _numElements; ++i) {
690         blitOp.cpuSourceBuffer = data;
691         blitOp.destinationByteOffset = vboOffset;
692 
693         stagingBuffer->StageCopy(blitOp);
694 
695         vboOffset += vboStride;
696         data += dataSize;
697     }
698 
699     HD_PERF_COUNTER_ADD(HdStPerfTokens->copyBufferCpuToGpu,
700                         (double)_numElements);
701 }
702 
703 VtValue
ReadData(TfToken const & name) const704 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::ReadData(
705     TfToken const &name) const
706 {
707     HD_TRACE_FUNCTION();
708     HF_MALLOC_TAG_FUNCTION();
709 
710     VtValue result;
711     if (!TF_VERIFY(_stripedBuffer)) return result;
712 
713     HdStBufferResourceSharedPtr VBO = _stripedBuffer->GetResource(name);
714 
715     if (!VBO || !VBO->GetHandle()) {
716         TF_CODING_ERROR("VBO doesn't exist for %s", name.GetText());
717         return result;
718     }
719 
720     result = HdStGLUtils::ReadBuffer(VBO->GetHandle()->GetRawResource(),
721                                    VBO->GetTupleType(),
722                                    VBO->GetOffset() + VBO->GetStride() * _index,
723                                    VBO->GetStride(),
724                                    _numElements);
725 
726     return result;
727 }
728 
729 size_t
GetMaxNumElements() const730 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetMaxNumElements() const
731 {
732     return _stripedBuffer->GetMaxNumElements();
733 }
734 
735 HdBufferArrayUsageHint
736 HdStInterleavedMemoryManager::
GetUsageHint() const737 _StripedInterleavedBufferRange::GetUsageHint() const
738 {
739     if (!TF_VERIFY(_stripedBuffer)) {
740         return HdBufferArrayUsageHint();
741     }
742 
743     return _stripedBuffer->GetUsageHint();
744 }
745 
746 HdStBufferResourceSharedPtr
GetResource() const747 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetResource() const
748 {
749     if (!TF_VERIFY(_stripedBuffer)) return HdStBufferResourceSharedPtr();
750 
751     return _stripedBuffer->GetResource();
752 }
753 
754 HdStBufferResourceSharedPtr
GetResource(TfToken const & name)755 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetResource(
756     TfToken const& name)
757 {
758     if (!TF_VERIFY(_stripedBuffer))
759         return HdStBufferResourceSharedPtr();
760 
761     // don't use GetResource(void) as a shortcut even an interleaved buffer
762     // is sharing one underlying GL resource. We may need an appropriate
763     // offset depending on name.
764     return _stripedBuffer->GetResource(name);
765 }
766 
767 HdStBufferResourceNamedList const&
GetResources() const768 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::GetResources() const
769 {
770     if (!TF_VERIFY(_stripedBuffer)) {
771         static HdStBufferResourceNamedList empty;
772         return empty;
773     }
774     return _stripedBuffer->GetResources();
775 }
776 
777 void
SetBufferArray(HdBufferArray * bufferArray)778 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::SetBufferArray(HdBufferArray *bufferArray)
779 {
780     _stripedBuffer = static_cast<_StripedInterleavedBuffer *>(bufferArray);
781 }
782 
783 void
DebugDump(std::ostream & out) const784 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::DebugDump(
785     std::ostream &out) const
786 {
787     out << "[StripedIBR] index = " << _index
788         << "\n";
789 }
790 
791 const void *
_GetAggregation() const792 HdStInterleavedMemoryManager::_StripedInterleavedBufferRange::_GetAggregation() const
793 {
794     return _stripedBuffer;
795 }
796 
797 PXR_NAMESPACE_CLOSE_SCOPE
798 
799