@@ -470,6 +470,8 @@ class IGPUTopLevelAccelerationStructure : public asset::ITopLevelAccelerationStr
470
470
// + an array of `PolymorphicInstance` if our `SCreationParams::flags.hasFlags(MOTION_BIT)`, otherwise
471
471
// + an array of `StaticInstance`
472
472
asset::SBufferBinding<const BufferType> instanceData = {};
473
+ // [optional] Provide info about what BLAS references to hold onto after the build
474
+ std::span<const IGPUBottomLevelAccelerationStructure*> trackedBLASes = {};
473
475
};
474
476
using DeviceBuildInfo = BuildInfo<IGPUBuffer>;
475
477
using HostBuildInfo = BuildInfo<asset::ICPUBuffer>;
@@ -545,11 +547,66 @@ class IGPUTopLevelAccelerationStructure : public asset::ITopLevelAccelerationStr
545
547
using HostPolymorphicInstance = PolymorphicInstance<IGPUBottomLevelAccelerationStructure::host_op_ref_t >;
546
548
static_assert (sizeof (DevicePolymorphicInstance)==sizeof (HostPolymorphicInstance));
547
549
550
+ //
551
+ using build_ver_t = uint32_t ;
552
+ // this gets called when execution is sure to happen 100%, e.g. not during command recording but during submission
553
+ inline build_ver_t nextBuildVer ()
554
+ {
555
+ return m_pendingBuildVer++;
556
+ }
557
+ //
558
+ using blas_smart_ptr_t = core::smart_refctd_ptr<const IGPUBottomLevelAccelerationStructure>;
559
+ // returns number of tracked BLASes if `tracked==nullptr` otherwise writes `*count` tracked BLASes from `first` into `*tracked`
560
+ inline build_ver_t getTrackedBLASes (uint32_t * count, blas_smart_ptr_t * tracked, const uint32_t first=0 ) const
561
+ {
562
+ if (!count)
563
+ return 0 ;
564
+ // stop multiple threads messing with us
565
+ std::lock_guard lk (m_trackingLock);
566
+ const uint32_t toWrite = std::min<uint32_t >(std::max<uint32_t >(m_trackedBLASes.size (),first)-first,tracked ? (*count):0xffFFffFFu );
567
+ *count = toWrite;
568
+ if (tracked && toWrite)
569
+ {
570
+ auto it = m_trackedBLASes.begin ();
571
+ // cmon its an unordered map, iterator should have operator +=
572
+ for (auto i=0 ; i<first; i++)
573
+ it++;
574
+ for (auto i=0 ; i<toWrite; i++)
575
+ *(tracked++) = *(it++);
576
+ }
577
+ return m_completedBuildVer;
578
+ }
579
+ // Useful if TLAS got built externally as well, returns if there were no later builds that preempted us setting the result here
580
+ template <typename Iterator>
581
+ inline bool setTrackedBLASes (const Iterator begin, const Iterator end, const build_ver_t buildVer)
582
+ {
583
+ // stop multiple threads messing with us
584
+ std::lock_guard lk (m_trackingLock);
585
+ // stop out of order callbacks
586
+ if (buildVer<=m_completedBuildVer)
587
+ return false ;
588
+ m_completedBuildVer = buildVer;
589
+ // release already tracked BLASes
590
+ m_trackedBLASes.clear ();
591
+ // sanity check, TODO: this should be an atomic_max on the `m_pendingBuildVer`
592
+ if (m_completedBuildVer>m_pendingBuildVer)
593
+ m_pendingBuildVer = m_completedBuildVer;
594
+ // now fill the contents
595
+ m_trackedBLASes.insert (begin,end);
596
+ return true ;
597
+ }
598
+
548
599
protected:
549
600
inline IGPUTopLevelAccelerationStructure (core::smart_refctd_ptr<const ILogicalDevice>&& dev, SCreationParams&& params)
550
- : asset::ITopLevelAccelerationStructure<IGPUAccelerationStructure>(std::move(dev),std::move(params)), m_maxInstanceCount(params.maxInstanceCount) {}
601
+ : asset::ITopLevelAccelerationStructure<IGPUAccelerationStructure>(std::move(dev),std::move(params)),
602
+ m_maxInstanceCount(params.maxInstanceCount),m_trackedBLASes() {}
551
603
552
604
const uint32_t m_maxInstanceCount;
605
+ // TODO: maybe replace with new readers/writers lock
606
+ mutable std::mutex m_trackingLock;
607
+ std::atomic<build_ver_t > m_pendingBuildVer = 0 ;
608
+ build_ver_t m_completedBuildVer = 0 ;
609
+ core::unordered_set<blas_smart_ptr_t > m_trackedBLASes;
553
610
};
554
611
555
612
}
0 commit comments