@@ -470,6 +470,8 @@ class IGPUTopLevelAccelerationStructure : public asset::ITopLevelAccelerationStr
470470 // + an array of `PolymorphicInstance` if our `SCreationParams::flags.hasFlags(MOTION_BIT)`, otherwise
471471 // + an array of `StaticInstance`
472472 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 = {};
473475 };
474476 using DeviceBuildInfo = BuildInfo<IGPUBuffer>;
475477 using HostBuildInfo = BuildInfo<asset::ICPUBuffer>;
@@ -545,11 +547,66 @@ class IGPUTopLevelAccelerationStructure : public asset::ITopLevelAccelerationStr
545547 using HostPolymorphicInstance = PolymorphicInstance<IGPUBottomLevelAccelerationStructure::host_op_ref_t >;
546548 static_assert (sizeof (DevicePolymorphicInstance)==sizeof (HostPolymorphicInstance));
547549
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+
548599 protected:
549600 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() {}
551603
552604 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;
553610};
554611
555612}
0 commit comments