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