@@ -76,7 +76,7 @@ void View::DrawThread( const TimelineContext& ctx, const ThreadData& thread, con
7676 if ( !draw.empty () && yPos <= yMax && yPos + ostep * croppedDepth >= yMin )
7777 {
7878 // Only apply margin when croppingActive to avoid text moving around when mouse is getting close to the cropper widget
79- DrawZoneList ( ctx, draw, offset, thread.id , croppedDepth, croppingActive ? cropperAdditionalMargin + GetScale () /* Ensure text has a bit of space for text */ : 0 .f );
79+ DrawZoneList ( ctx, draw, offset, thread.id , croppedDepth, croppingActive ? cropperAdditionalMargin + GetScale () /* Ensure text has a bit of space for text */ : 0 .f , thread. isFlatView != 0 );
8080 }
8181 offset += ostep * croppedDepth;
8282
@@ -227,7 +227,7 @@ void View::DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const
227227}
228228
229229
230- void View::DrawZoneList ( const TimelineContext& ctx, const std::vector<TimelineDraw>& drawList, int _offset, uint64_t tid, int maxDepth, double margin )
230+ void View::DrawZoneList ( const TimelineContext& ctx, const std::vector<TimelineDraw>& drawList, int _offset, uint64_t tid, int maxDepth, double margin, bool isFlatView )
231231{
232232 auto draw = ImGui::GetWindowDrawList ();
233233 const auto w = ctx.w ;
@@ -353,12 +353,23 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineD
353353
354354 const auto & seqRefMap = m_worker.GetZoneSeqRef ();
355355 const auto seqIt = seqRefMap.find ( &ev );
356- if ( seqIt != seqRefMap.end () )
356+ if ( !isFlatView && seqIt != seqRefMap.end () )
357357 {
358358 m_seqZoneYPos[&ev] = wpos.y + offset + ty * 0 .5f ;
359359 }
360360
361- const auto zoneColor = GetZoneColorData ( ev, tid, v.depth , v.inheritedColor );
361+ // Preserve original-thread coloring when rendered on a flat view.
362+ uint64_t colorTid = tid;
363+ if ( isFlatView && seqIt != seqRefMap.end () )
364+ {
365+ const auto & seqMap = m_worker.GetSequences ();
366+ auto sit = seqMap.find ( seqIt->second .seqId );
367+ if ( sit != seqMap.end () && seqIt->second .continuationIdx < sit->second ->continuations .size () )
368+ {
369+ colorTid = sit->second ->continuations [seqIt->second .continuationIdx ].tid ;
370+ }
371+ }
372+ const auto zoneColor = GetZoneColorData ( ev, colorTid, v.depth , v.inheritedColor );
362373 const char * zoneName = m_worker.GetZoneName ( ev );
363374
364375 auto tsz = ImGui::CalcTextSize ( zoneName );
@@ -392,7 +403,11 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineD
392403 if ( hover && ImGui::IsMouseHoveringRect ( wpos + ImVec2 ( px0, offset ), wpos + ImVec2 ( px1, offset + tsz.y + 1 ) ) )
393404 {
394405 ZoneTooltip ( ev );
395- if ( IsMouseClickReleased ( 1 ) ) m_setRangePopup = RangeSlim { ev.Start (), m_worker.GetZoneEnd ( ev ), true };
406+ if ( IsMouseClickReleased ( 1 ) )
407+ {
408+ m_setRangePopup = RangeSlim { ev.Start (), m_worker.GetZoneEnd ( ev ), true };
409+ m_seqFlattenPopupSeqId = ( !isFlatView && seqIt != seqRefMap.end () ) ? seqIt->second .seqId : 0 ;
410+ }
396411
397412 if ( !m_zoomAnim.active && IsMouseClicked ( 2 ) )
398413 {
@@ -414,7 +429,7 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineD
414429 m_zoneSrcLocHighlight = ev.SrcLoc ();
415430 m_zoneHover = &ev;
416431
417- if ( seqIt != seqRefMap.end () )
432+ if ( !isFlatView && seqIt != seqRefMap.end () )
418433 {
419434 const auto & seqMap = m_worker.GetSequences ();
420435 const auto sit = seqMap.find ( seqIt->second .seqId );
@@ -435,6 +450,7 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineD
435450 conts[idx+1 ].resumeTime , (const ZoneEvent*)conts[idx+1 ].zone } );
436451 }
437452 }
453+
438454 }
439455 }
440456 break ;
@@ -698,6 +714,72 @@ void View::DrawThreadCropper( const int depth, const uint64_t tid, const float x
698714 }
699715}
700716
717+ void View::MakeFlattenView ( uint64_t seqId )
718+ {
719+ for ( const auto & fv : m_flattenViews )
720+ {
721+ if ( fv.seqId == seqId ) return ; // idempotent
722+ }
723+ const auto & seqMap = m_worker.GetSequences ();
724+ auto sit = seqMap.find ( seqId );
725+ if ( sit == seqMap.end () || sit->second ->continuations .empty () ) return ;
726+ const auto & conts = sit->second ->continuations ;
727+
728+ const uint64_t synthTid = ( uint64_t (2 ) << 32 ) | m_nextFlattenTid++;
729+
730+ auto td = std::make_unique<ThreadData>();
731+ td->id = synthTid;
732+ td->count = 0 ;
733+ td->nextZoneId = 0 ;
734+ td->kernelSampleCnt = 0 ;
735+ td->isFiber = 0 ;
736+ td->isFlatView = 1 ;
737+ td->fiber = nullptr ;
738+ td->stackCount = nullptr ;
739+ td->groupHint = 0 ;
740+ #ifndef TRACY_NO_STATISTICS
741+ td->ghostIdx = 0 ;
742+ #endif
743+
744+ for ( const auto & c : conts )
745+ {
746+ td->timeline .push_back ( c.zone );
747+ }
748+
749+ char name[128 ];
750+ const auto * firstZone = (const ZoneEvent*)conts[0 ].zone ;
751+ const char * zName = m_worker.GetZoneName ( *firstZone );
752+ std::snprintf ( name, sizeof ( name ), " flat: %s" , zName ? zName : " ?" );
753+ m_worker.RegisterFlattenThreadName ( synthTid, name, strlen ( name ) );
754+
755+ m_flattenViews.push_back ( FlattenView{ std::move ( td ), seqId } );
756+ }
757+
758+ void View::DestroyFlattenView ( uint64_t seqId )
759+ {
760+ for ( auto it = m_flattenViews.begin (); it != m_flattenViews.end (); ++it )
761+ {
762+ if ( it->seqId == seqId )
763+ {
764+ m_worker.UnregisterFlattenThreadName ( it->td ->id );
765+ m_flattenViews.erase ( it );
766+ return ;
767+ }
768+ }
769+ }
770+
771+ void View::QueueDestroyFlattenViewByTid ( uint64_t tid )
772+ {
773+ for ( const auto & fv : m_flattenViews )
774+ {
775+ if ( fv.td ->id == tid )
776+ {
777+ m_flattenViewDestroyQueue.push_back ( fv.seqId );
778+ return ;
779+ }
780+ }
781+ }
782+
701783void View::DrawSeqArrows ( double pxns, const ImVec2& wpos )
702784{
703785 if ( m_seqArrowDraw.empty () ) return ;
0 commit comments