@@ -683,6 +683,167 @@ class ROFVertexLookupTable : public LayerTimingBase<NLayers>
683683 std::vector<TableEntry> mFlatTable ;
684684};
685685
686+ // GPU-friendly view of the ROF mask table
687+ template <int32_t NLayers>
688+ struct ROFMaskTableView {
689+ const uint8_t * mFlatMask {nullptr };
690+ const int32_t * mLayerROFOffsets {nullptr }; // size NLayers+1
691+
692+ GPUhdi () bool isROFEnabled (int32_t layer, int32_t rofId) const noexcept
693+ {
694+ assert (layer >= 0 && layer < NLayers);
695+ return mFlatMask [mLayerROFOffsets [layer] + rofId] != 0 ;
696+ }
697+
698+ #ifndef GPUCA_GPUCODE
699+ GPUh () void printAll() const
700+ {
701+ for (int32_t i = 0 ; i < NLayers; ++i) {
702+ printLayer (i);
703+ }
704+ }
705+
706+ GPUh () void printLayer(int32_t layer) const
707+ {
708+ constexpr int w_rof = 10 ;
709+ constexpr int w_active = 10 ;
710+ int32_t nROFs = mLayerROFOffsets [layer + 1 ] - mLayerROFOffsets [layer];
711+ LOGF (info, " Mask table: Layer %d" , layer);
712+ LOGF (info, " %*s | %*s" , w_rof, " ROF" , w_active, " Enabled" );
713+ LOGF (info, " %.*s-+-%.*s" , w_rof, " ----------" , w_active, " ----------" );
714+ for (int32_t i = 0 ; i < nROFs; ++i) {
715+ LOGF (info, " %*d | %*d" , w_rof, i, w_active, (int )isROFEnabled (layer, i));
716+ }
717+ }
718+ #endif
719+ };
720+
721+ // Per-ROF per-layer boolean mask (uint8_t for GPU compatibility).
722+ template <int32_t NLayers>
723+ class ROFMaskTable : public LayerTimingBase <NLayers>
724+ {
725+ public:
726+ using BCRange = dataformats::RangeReference<LayerTiming::BCType, LayerTiming::BCType>;
727+ using View = ROFMaskTableView<NLayers>;
728+
729+ GPUdDefault () ROFMaskTable() = default ;
730+ GPUh () explicit ROFMaskTable (const LayerTimingBase<NLayers>& timingBase) : LayerTimingBase<NLayers>(timingBase) { init (); }
731+
732+ GPUh () void init ()
733+ {
734+ int32_t totalROFs = 0 ;
735+ for (int32_t layer{0 }; layer < NLayers; ++layer) {
736+ mLayerROFOffsets [layer] = totalROFs;
737+ totalROFs += this ->getLayer (layer).mNROFsTF ;
738+ }
739+ mLayerROFOffsets [NLayers] = totalROFs; // sentinel
740+ mFlatMask .resize (totalROFs, 1 );
741+ }
742+
743+ GPUh () size_t getFlatMaskSize () const noexcept { return mFlatMask .size (); }
744+
745+ GPUh () bool isROFEnabled (int32_t layer, int32_t rofId) const noexcept { return mFlatMask [mLayerROFOffsets [layer] + rofId] != 0 ; }
746+
747+ GPUh () void setROFEnabled (int32_t layer, int32_t rofId, uint8_t state = 1 ) noexcept
748+ {
749+ assert (layer >= 0 && layer < NLayers);
750+ assert (rofId >= 0 && rofId < mLayerROFOffsets [layer + 1 ] - mLayerROFOffsets [layer]);
751+ mFlatMask [mLayerROFOffsets [layer] + rofId] = state;
752+ }
753+
754+ GPUh () void setROFsEnabled (int32_t layer, int32_t firstRof, int32_t nRofs, uint8_t state = 1 ) noexcept
755+ {
756+ assert (layer >= 0 && layer < NLayers);
757+ assert (firstRof >= 0 );
758+ assert (firstRof + nRofs <= mLayerROFOffsets [layer + 1 ] - mLayerROFOffsets [layer]);
759+ std::memset (mFlatMask .data () + mLayerROFOffsets [layer] + firstRof, state, nRofs);
760+ }
761+
762+ // Enable all ROFs in all layers that are time-compatible with the given BC range
763+ GPUh () void selectROF (const BCRange& t)
764+ {
765+ const int32_t bcStart = t.getFirstEntry ();
766+ const int32_t bcEnd = t.getEntriesBound ();
767+ for (int32_t layer{0 }; layer < NLayers; ++layer) {
768+ const auto & lay = this ->getLayer (layer);
769+ const int32_t offset = mLayerROFOffsets [layer];
770+ for (int32_t rofId{0 }; rofId < lay.mNROFsTF ; ++rofId) {
771+ if (static_cast <int32_t >(lay.getROFStartInBC (rofId)) < bcEnd &&
772+ static_cast <int32_t >(lay.getROFEndInBC (rofId)) > bcStart) {
773+ mFlatMask [offset + rofId] = 1 ;
774+ }
775+ }
776+ }
777+ }
778+
779+ // Reset mask to 0, then enable all ROFs compatible with any of the given BC ranges
780+ GPUh () void selectROFs (const std::vector<BCRange>& ts)
781+ {
782+ resetMask ();
783+ for (const auto & t : ts) {
784+ selectROF (t);
785+ }
786+ }
787+
788+ GPUh () void resetMask (uint8_t s = 0 )
789+ {
790+ std::memset (mFlatMask .data (), s, mFlatMask .size ());
791+ }
792+
793+ GPUh () void invertMask ()
794+ {
795+ std::ranges::transform (mFlatMask , mFlatMask .begin (), [](uint8_t x) { return 1 - x; });
796+ }
797+
798+ GPUh () void swap (ROFMaskTable& other) noexcept
799+ {
800+ std::swap (mFlatMask , other.mFlatMask );
801+ std::swap (mLayerROFOffsets , other.mLayerROFOffsets );
802+ }
803+
804+ GPUh () View getView () const
805+ {
806+ View view;
807+ view.mFlatMask = mFlatMask .data ();
808+ view.mLayerROFOffsets = mLayerROFOffsets ;
809+ return view;
810+ }
811+
812+ GPUh () View getDeviceView (const uint8_t * deviceFlatMaskPtr, const int32_t * deviceOffsetPtr) const
813+ {
814+ View view;
815+ view.mFlatMask = deviceFlatMaskPtr;
816+ view.mLayerROFOffsets = deviceOffsetPtr;
817+ return view;
818+ }
819+ #ifndef GPUCA_GPUCODE
820+ GPUh () std::string asString() const
821+ {
822+ std::string mask_str;
823+ for (int32_t i = 0 ; i < NLayers; ++i) {
824+ int32_t nROFs = mLayerROFOffsets [i + 1 ] - mLayerROFOffsets [i];
825+ int32_t enabledROFs = 0 ;
826+ for (int32_t j = 0 ; j < nROFs; ++j) {
827+ if (isROFEnabled (i, j)) {
828+ ++enabledROFs;
829+ }
830+ }
831+ mask_str += std::format (" Layer {} ROFs enabled: {}/{} | " , i, enabledROFs, nROFs);
832+ }
833+ return mask_str;
834+ }
835+
836+ GPUh () void print() const
837+ {
838+ LOG (info) << asString ();
839+ }
840+ #endif
841+
842+ private:
843+ int32_t mLayerROFOffsets [NLayers + 1 ]{}; // NLayers entries + 1 sentinel
844+ std::vector<uint8_t > mFlatMask ;
845+ };
846+
686847} // namespace o2::its
687848
688849#endif
0 commit comments