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/hdSt/vboMemoryManager.h"
25
26 #include "pxr/imaging/hdSt/bufferResource.h"
27 #include "pxr/imaging/hdSt/glUtils.h"
28 #include "pxr/imaging/hdSt/resourceRegistry.h"
29 #include "pxr/imaging/hdSt/tokens.h"
30 #include "pxr/imaging/hd/perfLog.h"
31 #include "pxr/imaging/hd/tokens.h"
32
33 #include "pxr/imaging/hf/perfLog.h"
34
35 #include "pxr/imaging/hgi/hgi.h"
36 #include "pxr/imaging/hgi/blitCmds.h"
37 #include "pxr/imaging/hgi/blitCmdsOps.h"
38 #include "pxr/imaging/hgi/buffer.h"
39
40 #include "pxr/base/arch/hash.h"
41 #include "pxr/base/tf/diagnostic.h"
42 #include "pxr/base/tf/envSetting.h"
43 #include "pxr/base/tf/iterator.h"
44 #include "pxr/base/tf/enum.h"
45
46 #include <vector>
47
48 PXR_NAMESPACE_OPEN_SCOPE
49
50
51 TF_DEFINE_ENV_SETTING(HD_MAX_VBO_SIZE, (1*1024*1024*1024),
52 "Maximum aggregated VBO size");
53
54 // ---------------------------------------------------------------------------
55 // HdStVBOMemoryManager
56 // ---------------------------------------------------------------------------
57 HdBufferArraySharedPtr
CreateBufferArray(TfToken const & role,HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint)58 HdStVBOMemoryManager::CreateBufferArray(
59 TfToken const &role,
60 HdBufferSpecVector const &bufferSpecs,
61 HdBufferArrayUsageHint usageHint)
62 {
63 return std::make_shared<HdStVBOMemoryManager::_StripedBufferArray>(
64 _resourceRegistry, role, bufferSpecs, usageHint);
65 }
66
67
68 HdBufferArrayRangeSharedPtr
CreateBufferArrayRange()69 HdStVBOMemoryManager::CreateBufferArrayRange()
70 {
71 return std::make_shared<_StripedBufferArrayRange>(_resourceRegistry);
72 }
73
74
75 HdAggregationStrategy::AggregationId
ComputeAggregationId(HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint) const76 HdStVBOMemoryManager::ComputeAggregationId(
77 HdBufferSpecVector const &bufferSpecs,
78 HdBufferArrayUsageHint usageHint) const
79 {
80 static size_t salt = ArchHash(__FUNCTION__, sizeof(__FUNCTION__));
81 size_t result = salt;
82 for (HdBufferSpec const &spec : bufferSpecs) {
83 boost::hash_combine(result, spec.Hash());
84 }
85
86 boost::hash_combine(result, usageHint.value);
87
88 // promote to size_t
89 return (AggregationId)result;
90 }
91
92
93 /// Returns the buffer specs from a given buffer array
94 HdBufferSpecVector
GetBufferSpecs(HdBufferArraySharedPtr const & bufferArray) const95 HdStVBOMemoryManager::GetBufferSpecs(
96 HdBufferArraySharedPtr const &bufferArray) const
97 {
98 _StripedBufferArraySharedPtr bufferArray_ =
99 std::static_pointer_cast<_StripedBufferArray> (bufferArray);
100 return bufferArray_->GetBufferSpecs();
101 }
102
103
104 /// Returns the size of the GPU memory used by the passed buffer array
105 size_t
GetResourceAllocation(HdBufferArraySharedPtr const & bufferArray,VtDictionary & result) const106 HdStVBOMemoryManager::GetResourceAllocation(
107 HdBufferArraySharedPtr const &bufferArray,
108 VtDictionary &result) const
109 {
110 std::set<uint64_t> idSet;
111 size_t gpuMemoryUsed = 0;
112
113 _StripedBufferArraySharedPtr bufferArray_ =
114 std::static_pointer_cast<_StripedBufferArray> (bufferArray);
115
116 TF_FOR_ALL(resIt, bufferArray_->GetResources()) {
117 HdStBufferResourceSharedPtr const & resource = resIt->second;
118 HgiBufferHandle buffer = resource->GetHandle();
119
120 // XXX avoid double counting of resources shared within a buffer
121 uint64_t id = buffer ? buffer->GetRawResource() : 0;
122 if (idSet.count(id) == 0) {
123 idSet.insert(id);
124
125 std::string const & role = resource->GetRole().GetString();
126 size_t size = size_t(resource->GetSize());
127
128 if (result.count(role)) {
129 size_t currentSize = result[role].Get<size_t>();
130 result[role] = VtValue(currentSize + size);
131 } else {
132 result[role] = VtValue(size);
133 }
134
135 gpuMemoryUsed += size;
136 }
137 }
138
139 return gpuMemoryUsed;
140 }
141
142
143 // ---------------------------------------------------------------------------
144 // _StripedBufferArray
145 // ---------------------------------------------------------------------------
_StripedBufferArray(HdStResourceRegistry * resourceRegistry,TfToken const & role,HdBufferSpecVector const & bufferSpecs,HdBufferArrayUsageHint usageHint)146 HdStVBOMemoryManager::_StripedBufferArray::_StripedBufferArray(
147 HdStResourceRegistry* resourceRegistry,
148 TfToken const &role,
149 HdBufferSpecVector const &bufferSpecs,
150 HdBufferArrayUsageHint usageHint)
151 : HdBufferArray(role, HdPerfTokens->garbageCollectedVbo, usageHint),
152 _resourceRegistry(resourceRegistry),
153 _needsCompaction(false),
154 _totalCapacity(0),
155 _maxBytesPerElement(0)
156 {
157 HD_TRACE_FUNCTION();
158 HF_MALLOC_TAG_FUNCTION();
159
160 /*
161 non-interleaved non-uniform buffer array (for example)
162 .------------------------------------------------------.
163 vec3 | pos.x (prim0) || pos.x (prim1) || ... |
164 | y || y || |
165 | z || z || |
166 '------------------------------------------------------'
167 .------------------------------------------------------.
168 vec4 | color.r (prim0) || color.r (prim1) || ... |
169 | g || g || |
170 | b || b || |
171 | a || a || |
172 '------------------------------------------------------'
173 ^--range0.numElements--^^--range1.numElements--^
174 |
175 ^-^ ^--range1.offset
176 stride
177 */
178
179 // populate BufferResources
180 TF_FOR_ALL(it, bufferSpecs) {
181 int stride = HdDataSizeOfTupleType(it->tupleType);
182 _AddResource(it->name, it->tupleType, /*offset*/0, stride);
183 }
184
185 // VBO Memory Manage supports an effectivly limitless set of ranges
186 _SetMaxNumRanges(std::numeric_limits<size_t>::max());
187
188 // compute max bytes / elements
189 TF_FOR_ALL (it, GetResources()) {
190 _maxBytesPerElement = std::max(
191 _maxBytesPerElement,
192 HdDataSizeOfTupleType(it->second->GetTupleType()));
193 }
194
195 // GetMaxNumElements() will crash with a divide by 0
196 // error if _maxBytesPerElement is 0.
197 //
198 // This can happen if bufferSpecs was empty and thus
199 // no resources were added. If means something went
200 // wrong earlier and we are just trying to survive.
201 if (!TF_VERIFY(_maxBytesPerElement != 0))
202 {
203 _maxBytesPerElement = 1;
204 }
205 }
206
207 HdStBufferResourceSharedPtr
_AddResource(TfToken const & name,HdTupleType tupleType,int offset,int stride)208 HdStVBOMemoryManager::_StripedBufferArray::_AddResource(TfToken const& name,
209 HdTupleType tupleType,
210 int offset,
211 int stride)
212 {
213 HD_TRACE_FUNCTION();
214 if (TfDebug::IsEnabled(HD_SAFE_MODE)) {
215 // duplication check
216 HdStBufferResourceSharedPtr bufferRes = GetResource(name);
217 if (!TF_VERIFY(!bufferRes)) {
218 return bufferRes;
219 }
220 }
221
222 HdStBufferResourceSharedPtr bufferRes =
223 std::make_shared<HdStBufferResource>(
224 GetRole(), tupleType, offset, stride);
225 _resourceList.emplace_back(name, bufferRes);
226 return bufferRes;
227 }
228
~_StripedBufferArray()229 HdStVBOMemoryManager::_StripedBufferArray::~_StripedBufferArray()
230 {
231 HD_TRACE_FUNCTION();
232 HF_MALLOC_TAG_FUNCTION();
233
234 // invalidate buffer array ranges in range list
235 // (these ranges may still be held by drawItems)
236 size_t rangeCount = GetRangeCount();
237 for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
238 _StripedBufferArrayRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx);
239
240 if (range) {
241 range->Invalidate();
242 }
243 }
244 }
245
246
247 bool
GarbageCollect()248 HdStVBOMemoryManager::_StripedBufferArray::GarbageCollect()
249 {
250 HD_TRACE_FUNCTION();
251 HF_MALLOC_TAG_FUNCTION();
252
253 if (_needsCompaction) {
254 RemoveUnusedRanges();
255
256 std::vector<HdBufferArrayRangeSharedPtr> ranges;
257 size_t rangeCount = GetRangeCount();
258 ranges.reserve(rangeCount);
259 for (size_t i = 0; i < rangeCount; ++i) {
260 HdBufferArrayRangeSharedPtr range = GetRange(i).lock();
261 if (range)
262 ranges.push_back(range);
263 }
264 Reallocate(ranges, shared_from_this());
265 }
266
267 if (GetRangeCount() == 0) {
268 _DeallocateResources();
269 return true;
270 }
271 return false;
272 }
273
274 void
Reallocate(std::vector<HdBufferArrayRangeSharedPtr> const & ranges,HdBufferArraySharedPtr const & curRangeOwner)275 HdStVBOMemoryManager::_StripedBufferArray::Reallocate(
276 std::vector<HdBufferArrayRangeSharedPtr> const &ranges,
277 HdBufferArraySharedPtr const &curRangeOwner)
278 {
279 HD_TRACE_FUNCTION();
280 HF_MALLOC_TAG_FUNCTION();
281
282 HD_PERF_COUNTER_INCR(HdPerfTokens->vboRelocated);
283
284 _StripedBufferArraySharedPtr curRangeOwner_ =
285 std::static_pointer_cast<_StripedBufferArray> (curRangeOwner);
286
287 if (!TF_VERIFY(GetResources().size() ==
288 curRangeOwner_->GetResources().size())) {
289 TF_CODING_ERROR("Resource mismatch when reallocating buffer array");
290 return;
291 }
292
293 if (TfDebug::IsEnabled(HD_SAFE_MODE)) {
294 HdStBufferResourceNamedList::size_type bresIdx = 0;
295 TF_FOR_ALL(bresIt, GetResources()) {
296 TF_VERIFY(curRangeOwner_->GetResources()[bresIdx++].second ==
297 curRangeOwner_->GetResource(bresIt->first));
298 }
299 }
300
301 // count up total elements and update new offsets
302 size_t totalNumElements = 0;
303 std::vector<size_t> newOffsets;
304 newOffsets.reserve(ranges.size());
305
306 TF_FOR_ALL (it, ranges) {
307 HdBufferArrayRangeSharedPtr const &range = *it;
308 if (!range) {
309 TF_CODING_ERROR("Expired range found in the reallocation list");
310 continue;
311 }
312
313 // save new offset
314 newOffsets.push_back(totalNumElements);
315
316 // XXX: always tightly pack for now.
317 totalNumElements += range->GetNumElements();
318 }
319
320 // update range list (should be done before early exit)
321 _SetRangeList(ranges);
322
323 _totalCapacity = totalNumElements;
324
325 Hgi* hgi = _resourceRegistry->GetHgi();
326 HgiBlitCmds* blitCmds = _resourceRegistry->GetGlobalBlitCmds();
327 blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__);
328
329 // resize each BufferResource
330 HdStBufferResourceNamedList const& resources = GetResources();
331 for (size_t bresIdx=0; bresIdx<resources.size(); ++bresIdx) {
332 HdStBufferResourceSharedPtr const &bres = resources[bresIdx].second;
333 HdStBufferResourceSharedPtr const &curRes =
334 curRangeOwner_->GetResources()[bresIdx].second;
335
336 int bytesPerElement = HdDataSizeOfTupleType(bres->GetTupleType());
337 TF_VERIFY(bytesPerElement > 0);
338 size_t bufferSize = bytesPerElement * _totalCapacity;
339
340 // allocate new one
341 // curBuf and oldBuf will be different when we are adopting ranges
342 // from another buffer array.
343 HgiBufferHandle& oldBuf = bres->GetHandle();
344 HgiBufferHandle& curBuf = curRes->GetHandle();
345 HgiBufferHandle newBuf;
346
347 // Skip buffers of zero size
348 if (bufferSize > 0) {
349 HgiBufferDesc bufDesc;
350 bufDesc.usage = HgiBufferUsageUniform;
351 bufDesc.byteSize = bufferSize;
352 newBuf = hgi->CreateBuffer(bufDesc);
353 }
354
355 // if old and new buffer exist, copy unchanged data
356 if (curBuf && newBuf) {
357 std::vector<size_t>::iterator newOffsetIt = newOffsets.begin();
358
359 // pre-pass to combine consecutive buffer range relocation
360 HdStBufferRelocator relocator(curBuf, newBuf);
361 TF_FOR_ALL (it, ranges) {
362 _StripedBufferArrayRangeSharedPtr range =
363 std::static_pointer_cast<_StripedBufferArrayRange>(*it);
364 if (!range) {
365 TF_CODING_ERROR("_StripedBufferArrayRange "
366 "expired unexpectedly.");
367 continue;
368 }
369
370 // copy the range. There are three cases:
371 //
372 // 1. src length (capacity) == dst length (numElements)
373 // Copy the entire range
374 //
375 // 2. src length < dst length
376 // Enlarging the range. This typically happens when
377 // applying quadrangulation/subdivision to populate
378 // additional data at the end of source data.
379 //
380 // 3. src length > dst length
381 // Shrinking the range. When the garbage collection
382 // truncates ranges.
383 //
384 int oldSize = range->GetCapacity();
385 int newSize = range->GetNumElements();
386 ptrdiff_t copySize =
387 std::min(oldSize, newSize) * bytesPerElement;
388 int oldOffset = range->GetElementOffset();
389 if (copySize > 0) {
390 ptrdiff_t readOffset = oldOffset * bytesPerElement;
391 ptrdiff_t writeOffset = *newOffsetIt * bytesPerElement;
392
393 relocator.AddRange(readOffset, writeOffset, copySize);
394 }
395 ++newOffsetIt;
396 }
397
398 // buffer copy
399 relocator.Commit(blitCmds);
400 }
401 if (oldBuf) {
402 // delete old buffer
403 hgi->DestroyBuffer(&oldBuf);
404 }
405
406 // update allocation of buffer resource
407 bres->SetAllocation(newBuf, bufferSize);
408 }
409
410 // update ranges
411 for (size_t idx = 0; idx < ranges.size(); ++idx) {
412 _StripedBufferArrayRangeSharedPtr range =
413 std::static_pointer_cast<_StripedBufferArrayRange>(ranges[idx]);
414 if (!range) {
415 TF_CODING_ERROR("_StripedBufferArrayRange expired unexpectedly.");
416 continue;
417 }
418 range->SetElementOffset(newOffsets[idx]);
419 range->SetCapacity(range->GetNumElements());
420 }
421
422 blitCmds->PopDebugGroup();
423
424 _needsReallocation = false;
425 _needsCompaction = false;
426
427 // increment version to rebuild dispatch buffers.
428 IncrementVersion();
429 }
430
431 void
_DeallocateResources()432 HdStVBOMemoryManager::_StripedBufferArray::_DeallocateResources()
433 {
434 Hgi* hgi = _resourceRegistry->GetHgi();
435 TF_FOR_ALL (it, GetResources()) {
436 hgi->DestroyBuffer(&it->second->GetHandle());
437 }
438 }
439
440 /*virtual*/
441 size_t
GetMaxNumElements() const442 HdStVBOMemoryManager::_StripedBufferArray::GetMaxNumElements() const
443 {
444 static size_t vboMaxSize = TfGetEnvSetting(HD_MAX_VBO_SIZE);
445 return vboMaxSize / _maxBytesPerElement;
446 }
447
448 void
DebugDump(std::ostream & out) const449 HdStVBOMemoryManager::_StripedBufferArray::DebugDump(std::ostream &out) const
450 {
451 out << " HdStVBOMemoryManager\n";
452 out << " total capacity = " << _totalCapacity << "\n";
453 out << " Range entries " << GetRangeCount() << ":\n";
454
455 size_t rangeCount = GetRangeCount();
456 for (size_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
457 _StripedBufferArrayRangeSharedPtr range = _GetRangeSharedPtr(rangeIdx);
458 if (range) {
459 out << " " << rangeIdx << *range;
460 }
461 }
462 }
463
464 HdStBufferResourceSharedPtr
GetResource() const465 HdStVBOMemoryManager::_StripedBufferArray::GetResource() const
466 {
467 HD_TRACE_FUNCTION();
468
469 if (_resourceList.empty()) return HdStBufferResourceSharedPtr();
470
471 if (TfDebug::IsEnabled(HD_SAFE_MODE)) {
472 // make sure this buffer array has only one resource.
473 HgiBufferHandle const& buffer =
474 _resourceList.begin()->second->GetHandle();
475 TF_FOR_ALL (it, _resourceList) {
476 if (it->second->GetHandle() != buffer) {
477 TF_CODING_ERROR("GetResource(void) called on"
478 "HdBufferArray having multiple GPU resources");
479 }
480 }
481 }
482
483 // returns the first item
484 return _resourceList.begin()->second;
485 }
486
487 HdStBufferResourceSharedPtr
GetResource(TfToken const & name)488 HdStVBOMemoryManager::_StripedBufferArray::GetResource(TfToken const& name)
489 {
490 HD_TRACE_FUNCTION();
491
492 // linear search.
493 // The number of buffer resources should be small (<10 or so).
494 for (HdStBufferResourceNamedList::iterator it = _resourceList.begin();
495 it != _resourceList.end(); ++it) {
496 if (it->first == name) return it->second;
497 }
498 return HdStBufferResourceSharedPtr();
499 }
500
501 HdBufferSpecVector
GetBufferSpecs() const502 HdStVBOMemoryManager::_StripedBufferArray::GetBufferSpecs() const
503 {
504 HdBufferSpecVector result;
505 result.reserve(_resourceList.size());
506 TF_FOR_ALL (it, _resourceList) {
507 result.emplace_back(it->first, it->second->GetTupleType());
508 }
509 return result;
510 }
511
512 // ---------------------------------------------------------------------------
513 // _StripedBufferArrayRange
514 // ---------------------------------------------------------------------------
~_StripedBufferArrayRange()515 HdStVBOMemoryManager::_StripedBufferArrayRange::~_StripedBufferArrayRange()
516 {
517 // Notify that hosting buffer array needs to be garbage collected.
518 //
519 // Don't do any substantial work here.
520 //
521 if (_stripedBufferArray) {
522 _stripedBufferArray->SetNeedsCompaction();
523
524 // notify source bufferArray to bump the version so that
525 // drawbatches to be rebuilt.
526 // Also note that the buffer migration takes place only in
527 // this StripedBufferArray, not in other InterleavedVBO/SimpleVBO.
528 _stripedBufferArray->IncrementVersion();
529 }
530 }
531
532
533 bool
IsAssigned() const534 HdStVBOMemoryManager::_StripedBufferArrayRange::IsAssigned() const
535 {
536 return (_stripedBufferArray != nullptr);
537 }
538
539 bool
IsImmutable() const540 HdStVBOMemoryManager::_StripedBufferArrayRange::IsImmutable() const
541 {
542 return (_stripedBufferArray != nullptr)
543 && _stripedBufferArray->IsImmutable();
544 }
545
546 bool
RequiresStaging() const547 HdStVBOMemoryManager::_StripedBufferArrayRange::RequiresStaging() const
548 {
549 return false;
550 }
551
552 bool
Resize(int numElements)553 HdStVBOMemoryManager::_StripedBufferArrayRange::Resize(int numElements)
554 {
555 HD_TRACE_FUNCTION();
556 HF_MALLOC_TAG_FUNCTION();
557
558 if (!TF_VERIFY(_stripedBufferArray)) return false;
559
560 bool needsReallocation = false;
561
562 // XXX: varying topology points fix (bug 114080)
563 //
564 // MDI draw uses a dispatch buffer, and it includes numElements to be
565 // drawn. When a topology is varying, numElements will change so the
566 // dispatch buffer has to be rebuilt. Currently we depend on entire
567 // buffer reallocation for index-drawing prims (e.g. meshes and curves)
568 // with varying topology. We always allocate new BARs for them,
569 // which is inefficient, and will be addressed later (bug 103767)
570 //
571 // However varying points have another problem: When it reduces its
572 // number of points, it doesn't cause the reallocation in the below code
573 // (disabled by #if 0) since points don't have an index buffer.
574 //
575 // These two problems have to be solved together by introducing more
576 // robust mechanism which updates dispatch buffer partially to
577 // reflect numElements correctly without having reallocation.
578 // It needs more works, until then, we invoke reallocation whenever
579 // numElements changes in an aggregated buffer, for the correctness
580 // problem of points drawing (this is bug 114080).
581 //
582 // The varying mesh batch may suffer a performance regression
583 // from this treatment, but it should be relatively small. Because the
584 // topology buffer has already been reallocated on every changes as
585 // described above and the primvar buffer is also reallocated in
586 // GarbageCollect() before drawing (see HdEngine::Draw()).
587 //
588 // We need to revisit to clean this up soon.
589 //
590 #if 0
591 if (_capacity < numElements) {
592 // mark entire buffer array to be relocated
593 _stripedBufferArray->SetNeedsReallocation();
594 needsReallocation = true;
595 } else if (_capacity > numElements) {
596 // mark the buffer array can be compacted
597 _stripedBufferArray->SetNeedsCompaction();
598 }
599 #else
600 if (_capacity != numElements) {
601 const size_t numMaxElements = GetMaxNumElements();
602
603 if (static_cast<size_t>(numElements) > numMaxElements) {
604 TF_WARN("Attempting to resize the BAR with 0x%x elements when the "
605 "max number of elements in the buffer array is 0x%lx. "
606 "Clamping BAR size to the latter.",
607 numElements, numMaxElements);
608
609 numElements = numMaxElements;
610 }
611 _stripedBufferArray->SetNeedsReallocation();
612 needsReallocation = true;
613 }
614 #endif
615
616 _numElements = numElements;
617 return needsReallocation;
618 }
619
620 void
CopyData(HdBufferSourceSharedPtr const & bufferSource)621 HdStVBOMemoryManager::_StripedBufferArrayRange::CopyData(
622 HdBufferSourceSharedPtr const &bufferSource)
623 {
624 HD_TRACE_FUNCTION();
625 HF_MALLOC_TAG_FUNCTION();
626
627 if (!TF_VERIFY(_stripedBufferArray)) return;
628
629 HdStBufferResourceSharedPtr VBO =
630 _stripedBufferArray->GetResource(bufferSource->GetName());
631
632 if (!TF_VERIFY((VBO && VBO->GetHandle()),
633 "VBO doesn't exist for %s",
634 bufferSource->GetName().GetText())) {
635 return;
636 }
637
638 // datatype of bufferSource has to match with bufferResource
639 if (!TF_VERIFY(bufferSource->GetTupleType() == VBO->GetTupleType(),
640 "'%s': (%s (%i) x %zu) != (%s (%i) x %zu)\n",
641 bufferSource->GetName().GetText(),
642 TfEnum::GetName(bufferSource->GetTupleType().type).c_str(),
643 bufferSource->GetTupleType().type,
644 bufferSource->GetTupleType().count,
645 TfEnum::GetName(VBO->GetTupleType().type).c_str(),
646 VBO->GetTupleType().type,
647 VBO->GetTupleType().count)) {
648 return;
649 }
650
651 int bytesPerElement = HdDataSizeOfTupleType(VBO->GetTupleType());
652
653 // overrun check. for graceful handling of erroneous assets,
654 // issue warning here and continue to copy for the valid range.
655 size_t dstSize = _numElements * bytesPerElement;
656 size_t srcSize =
657 bufferSource->GetNumElements() *
658 HdDataSizeOfTupleType(bufferSource->GetTupleType());
659 if (srcSize > dstSize) {
660 TF_WARN("%s: size %ld is larger than the range (%ld)",
661 bufferSource->GetName().GetText(), srcSize, dstSize);
662 srcSize = dstSize;
663 }
664 size_t vboOffset = bytesPerElement * _elementOffset;
665
666 HD_PERF_COUNTER_INCR(HdStPerfTokens->copyBufferCpuToGpu);
667
668 HgiBufferCpuToGpuOp blitOp;
669 blitOp.cpuSourceBuffer = bufferSource->GetData();
670 blitOp.gpuDestinationBuffer = VBO->GetHandle();
671
672 blitOp.sourceByteOffset = 0;
673 blitOp.byteSize = srcSize;
674 blitOp.destinationByteOffset = vboOffset;
675
676 HgiBlitCmds* blitCmds = GetResourceRegistry()->GetGlobalBlitCmds();
677 blitCmds->PushDebugGroup(__ARCH_PRETTY_FUNCTION__);
678 blitCmds->CopyBufferCpuToGpu(blitOp);
679 blitCmds->PopDebugGroup();
680 }
681
682 int
GetByteOffset(TfToken const & resourceName) const683 HdStVBOMemoryManager::_StripedBufferArrayRange::GetByteOffset(
684 TfToken const& resourceName) const
685 {
686 if (!TF_VERIFY(_stripedBufferArray)) return 0;
687 HdStBufferResourceSharedPtr VBO =
688 _stripedBufferArray->GetResource(resourceName);
689
690 if (!VBO || (!VBO->GetHandle() && _numElements > 0)) {
691 TF_CODING_ERROR("VBO doesn't exist for %s", resourceName.GetText());
692 return 0;
693 }
694
695 return (int) _GetByteOffset(VBO);
696 }
697
698 VtValue
ReadData(TfToken const & name) const699 HdStVBOMemoryManager::_StripedBufferArrayRange::ReadData(TfToken const &name) const
700 {
701 HD_TRACE_FUNCTION();
702 HF_MALLOC_TAG_FUNCTION();
703
704 VtValue result;
705 if (!TF_VERIFY(_stripedBufferArray)) return result;
706
707 HdStBufferResourceSharedPtr VBO = _stripedBufferArray->GetResource(name);
708
709 if (!VBO || (!VBO->GetHandle() && _numElements > 0)) {
710 TF_CODING_ERROR("VBO doesn't exist for %s", name.GetText());
711 return result;
712 }
713
714 size_t vboOffset = _GetByteOffset(VBO);
715
716 uint64_t vbo = VBO->GetHandle() ? VBO->GetHandle()->GetRawResource() : 0;
717
718 result = HdStGLUtils::ReadBuffer(vbo,
719 VBO->GetTupleType(),
720 vboOffset,
721 /*stride=*/0, // not interleaved.
722 _numElements);
723
724 return result;
725 }
726
727 size_t
GetMaxNumElements() const728 HdStVBOMemoryManager::_StripedBufferArrayRange::GetMaxNumElements() const
729 {
730 return _stripedBufferArray->GetMaxNumElements();
731 }
732
733 HdBufferArrayUsageHint
GetUsageHint() const734 HdStVBOMemoryManager::_StripedBufferArrayRange::GetUsageHint() const
735 {
736 if (!TF_VERIFY(_stripedBufferArray)) {
737 return HdBufferArrayUsageHint();
738 }
739
740 return _stripedBufferArray->GetUsageHint();
741 }
742
743
744 HdStBufferResourceSharedPtr
GetResource() const745 HdStVBOMemoryManager::_StripedBufferArrayRange::GetResource() const
746 {
747 if (!TF_VERIFY(_stripedBufferArray)) return HdStBufferResourceSharedPtr();
748
749 return _stripedBufferArray->GetResource();
750 }
751
752 HdStBufferResourceSharedPtr
GetResource(TfToken const & name)753 HdStVBOMemoryManager::_StripedBufferArrayRange::GetResource(TfToken const& name)
754 {
755 if (!TF_VERIFY(_stripedBufferArray)) return HdStBufferResourceSharedPtr();
756
757 return _stripedBufferArray->GetResource(name);
758 }
759
760 HdStBufferResourceNamedList const&
GetResources() const761 HdStVBOMemoryManager::_StripedBufferArrayRange::GetResources() const
762 {
763 if (!TF_VERIFY(_stripedBufferArray)) {
764 static HdStBufferResourceNamedList empty;
765 return empty;
766 }
767 return _stripedBufferArray->GetResources();
768 }
769
770 void
SetBufferArray(HdBufferArray * bufferArray)771 HdStVBOMemoryManager::_StripedBufferArrayRange::SetBufferArray(HdBufferArray *bufferArray)
772 {
773 _stripedBufferArray = static_cast<_StripedBufferArray *>(bufferArray);
774 }
775
776 void
DebugDump(std::ostream & out) const777 HdStVBOMemoryManager::_StripedBufferArrayRange::DebugDump(std::ostream &out) const
778 {
779 out << "[StripedBAR] offset = " << _elementOffset
780 << ", numElements = " << _numElements
781 << ", capacity = " << _capacity
782 << "\n";
783 }
784
785 const void *
_GetAggregation() const786 HdStVBOMemoryManager::_StripedBufferArrayRange::_GetAggregation() const
787 {
788 return _stripedBufferArray;
789 }
790
791 size_t
_GetByteOffset(HdStBufferResourceSharedPtr const & resource) const792 HdStVBOMemoryManager::_StripedBufferArrayRange::_GetByteOffset(
793 HdStBufferResourceSharedPtr const& resource) const
794 {
795 return HdDataSizeOfTupleType(resource->GetTupleType()) * _elementOffset;
796 }
797
798 PXR_NAMESPACE_CLOSE_SCOPE
799
800