From 30fd92de0f2f248eb50e1714a867a9eee0f87fa5 Mon Sep 17 00:00:00 2001 From: rmarker Date: Thu, 28 May 2026 21:59:33 +0930 Subject: [PATCH] Handle partial panning in flame graph view. When zoomed in very far the panning resolution can be so small that it is less than one unit. In order to continue panning, we store partial pans so that they can accumulate across frames. --- profiler/src/profiler/TracyView.hpp | 1 + .../src/profiler/TracyView_FlameGraph.cpp | 49 ++++++++++++++----- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/profiler/src/profiler/TracyView.hpp b/profiler/src/profiler/TracyView.hpp index 69c3537f..914cee52 100644 --- a/profiler/src/profiler/TracyView.hpp +++ b/profiler/src/profiler/TracyView.hpp @@ -993,6 +993,7 @@ private: std::vector m_flameGraphData; int64_t m_flameGraphViewStart = 0; int64_t m_flameGraphViewEnd = 0; + double m_flameGraphPan = 0; struct { uint64_t count = 0; diff --git a/profiler/src/profiler/TracyView_FlameGraph.cpp b/profiler/src/profiler/TracyView_FlameGraph.cpp index a09bda26..c2a15a64 100644 --- a/profiler/src/profiler/TracyView_FlameGraph.cpp +++ b/profiler/src/profiler/TracyView_FlameGraph.cpp @@ -740,7 +740,19 @@ void View::DrawFlameGraphHeader( int64_t vStart, int64_t vEnd, uint64_t period ) } } -static void DrawFlameGraphHorizontalPosition( int64_t& vStart, int64_t& vEnd, int64_t totalSpan, uint64_t period ) +static bool ApplyFlameGraphPan( int64_t& start, int64_t& end, double& pan, double delta ) +{ + pan += delta; + const auto d = int64_t( pan ); + if( d == 0 ) return false; + + start += d; + end += d; + pan -= d; + return true; +} + +static void DrawFlameGraphHorizontalPosition( int64_t& vStart, int64_t& vEnd, double& pan, int64_t totalSpan, uint64_t period ) { assert( vStart < vEnd ); assert( totalSpan > 0 ); @@ -800,12 +812,7 @@ static void DrawFlameGraphHorizontalPosition( int64_t& vStart, int64_t& vEnd, in if( active && ImGui::IsMouseDragging( 0 ) ) { const auto delta = ImGui::GetIO().MouseDelta.x; - const auto d = int64_t( delta * totalSpan / w ); - if( d != 0 ) - { - vStart += d; - vEnd += d; - } + ApplyFlameGraphPan( vStart, vEnd, pan, delta * totalSpan / w ); } } @@ -909,6 +916,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } if( m_worker.AreCallstackSamplesReady() && m_worker.GetCallstackSampleCount() > 0 ) @@ -919,6 +927,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } } @@ -931,6 +940,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } if( m_flameMode == 0 ) @@ -943,6 +953,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } } else @@ -962,6 +973,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } ImGui::SameLine(); if( m_flameExternal ) ImGui::BeginDisabled(); @@ -970,6 +982,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } if( m_flameExternal ) ImGui::EndDisabled(); } @@ -989,6 +1002,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } if( m_flameRange.active ) { @@ -1006,6 +1020,7 @@ void View::DrawFlameGraph() { m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } auto& td = m_worker.GetThreadData(); @@ -1038,6 +1053,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } ImGui::SameLine(); if( ImGui::SmallButton( "Unselect all" ) ) @@ -1049,6 +1065,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } const auto& style = ImGui::GetStyle(); @@ -1081,6 +1098,7 @@ void View::DrawFlameGraph() m_flameGraphInvariant.Reset(); m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } ImGui::PopID(); if( t->isFiber ) @@ -1108,6 +1126,7 @@ void View::DrawFlameGraph() { m_flameGraphViewStart = 0; m_flameGraphViewEnd = 0; + m_flameGraphPan = 0; } m_flameGraphInvariant.range = m_flameRange; @@ -1199,15 +1218,17 @@ void View::DrawFlameGraph() { m_flameGraphViewStart = 0; m_flameGraphViewEnd = zsz; + m_flameGraphPan = 0; } else if( flameDataRebuilt && oldZsz > 0 && m_flameGraphViewStart == 0 && m_flameGraphViewEnd == oldZsz ) { m_flameGraphViewEnd = zsz; + m_flameGraphPan = 0; } const auto period = m_flameMode == 0 ? 1 : m_worker.GetSamplingPeriod(); DrawFlameGraphHeader( m_flameGraphViewStart, m_flameGraphViewEnd, period ); - DrawFlameGraphHorizontalPosition( m_flameGraphViewStart, m_flameGraphViewEnd, zsz, period ); + DrawFlameGraphHorizontalPosition( m_flameGraphViewStart, m_flameGraphViewEnd, m_flameGraphPan, zsz, period ); ClampFlameGraphViewport( m_flameGraphViewStart, m_flameGraphViewEnd, zsz ); ImGui::BeginChild( "##flameGraphBody", ImVec2( 0, 0 ), false, ImGuiWindowFlags_NoScrollWithMouse ); @@ -1235,13 +1256,14 @@ void View::DrawFlameGraph() { const auto delta = GetMouseDragDelta( 1 ); const auto hwheel_delta = io.MouseWheelH * 50.f * m_horizontalScrollMultiplier; - const auto dpx = int64_t( delta.x * nspx + hwheel_delta * nspx ); - if( dpx != 0 ) + if( delta.x != 0 || hwheel_delta != 0 ) { - m_flameGraphViewStart -= dpx; - m_flameGraphViewEnd -= dpx; + const auto changed = ApplyFlameGraphPan( m_flameGraphViewStart, m_flameGraphViewEnd, m_flameGraphPan, -( delta.x + hwheel_delta ) * nspx ); io.MouseClickedPos[1].x = io.MousePos.x; - ClampFlameGraphViewport( m_flameGraphViewStart, m_flameGraphViewEnd, zsz ); + if( changed ) + { + ClampFlameGraphViewport( m_flameGraphViewStart, m_flameGraphViewEnd, zsz ); + } } if( delta.y != 0 ) @@ -1254,6 +1276,7 @@ void View::DrawFlameGraph() const bool wheel_zoom = fabs( io.MouseWheel ) > fabs( io.MouseWheelH ); if( hover && wheel_zoom ) { + m_flameGraphPan = 0; const auto wheel = io.MouseWheel; const auto mouse = io.MousePos.x - wpos.x; const auto p = mouse / w;