diff --git a/profiler/build/win32/Tracy.vcxproj b/profiler/build/win32/Tracy.vcxproj index c324f225..d746d984 100644 --- a/profiler/build/win32/Tracy.vcxproj +++ b/profiler/build/win32/Tracy.vcxproj @@ -142,6 +142,7 @@ + diff --git a/profiler/build/win32/Tracy.vcxproj.filters b/profiler/build/win32/Tracy.vcxproj.filters index 81f20cb2..77f61e5d 100644 --- a/profiler/build/win32/Tracy.vcxproj.filters +++ b/profiler/build/win32/Tracy.vcxproj.filters @@ -282,6 +282,9 @@ server + + server + diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 22a773d7..8e45c53f 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -1670,451 +1670,6 @@ bool View::DrawConnection() return true; } -enum { BestTime = 1000 * 1000 * 1000 / 143 }; -enum { GoodTime = 1000 * 1000 * 1000 / 59 }; -enum { BadTime = 1000 * 1000 * 1000 / 29 }; - -static ImU32 GetFrameColor( uint64_t frameTime ) -{ - return frameTime > BadTime ? 0xFF2222DD : - frameTime > GoodTime ? 0xFF22DDDD : - frameTime > BestTime ? 0xFF22DD22 : 0xFFDD9900; -} - -static int GetFrameWidth( int frameScale ) -{ - return frameScale == 0 ? 4 : ( frameScale < 0 ? 6 : 1 ); -} - -static int GetFrameGroup( int frameScale ) -{ - return frameScale < 2 ? 1 : ( 1 << ( frameScale - 1 ) ); -} - -template -constexpr const T& clamp( const T& v, const T& lo, const T& hi ) -{ - return v < lo ? lo : v > hi ? hi : v; -} - -void View::DrawFrames() -{ - assert( m_worker.GetFrameCount( *m_frames ) != 0 ); - - const auto scale = GetScale(); - const auto Height = 50 * scale; - - enum { MaxFrameTime = 50 * 1000 * 1000 }; // 50ms - - ImGuiWindow* window = ImGui::GetCurrentWindowRead(); - if( window->SkipItems ) return; - - auto& io = ImGui::GetIO(); - - const auto wpos = ImGui::GetCursorScreenPos(); - const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); - const auto wspace = ImGui::GetWindowContentRegionMax() - ImGui::GetWindowContentRegionMin(); - const auto w = wspace.x; - auto draw = ImGui::GetWindowDrawList(); - - ImGui::InvisibleButton( "##frames", ImVec2( w, Height ) ); - bool hover = ImGui::IsItemHovered(); - - draw->AddRectFilled( wpos, wpos + ImVec2( w, Height ), 0x33FFFFFF ); - const auto wheel = io.MouseWheel; - const auto prevScale = m_vd.frameScale; - if( hover ) - { - if( wheel > 0 ) - { - if( m_vd.frameScale >= 0 ) m_vd.frameScale--; - } - else if( wheel < 0 ) - { - if( m_vd.frameScale < 10 ) m_vd.frameScale++; - } - } - - const int fwidth = GetFrameWidth( m_vd.frameScale ); - const int group = GetFrameGroup( m_vd.frameScale ); - const int total = m_worker.GetFrameCount( *m_frames ); - const int onScreen = ( w - 2 ) / fwidth; - if( m_viewMode != ViewMode::Paused ) - { - m_vd.frameStart = ( total < onScreen * group ) ? 0 : total - onScreen * group; - if( m_viewMode == ViewMode::LastFrames ) - { - SetViewToLastFrames(); - } - else - { - assert( m_viewMode == ViewMode::LastRange ); - const auto delta = m_worker.GetLastTime() - m_vd.zvEnd; - if( delta != 0 ) - { - m_vd.zvStart += delta; - m_vd.zvEnd += delta; - } - } - } - - if( hover ) - { - const auto hwheel_delta = io.MouseWheelH * 100.f; - if( IsMouseDragging( 1 ) || hwheel_delta != 0 ) - { - m_viewMode = ViewMode::Paused; - m_viewModeHeuristicTry = false; - auto delta = GetMouseDragDelta( 1 ).x; - if( delta == 0 ) delta = hwheel_delta; - if( abs( delta ) >= fwidth ) - { - const auto d = (int)delta / fwidth; - m_vd.frameStart = std::max( 0, m_vd.frameStart - d * group ); - io.MouseClickedPos[1].x = io.MousePos.x + d * fwidth - delta; - } - } - - const auto mx = io.MousePos.x; - if( mx > wpos.x && mx < wpos.x + w - 1 ) - { - const auto mo = mx - ( wpos.x + 1 ); - const auto off = mo * group / fwidth; - - const int sel = m_vd.frameStart + off; - if( sel < total ) - { - ImGui::BeginTooltip(); - if( group > 1 ) - { - auto f = m_worker.GetFrameTime( *m_frames, sel ); - auto g = std::min( group, total - sel ); - for( int j=1; jname == 0 ) - { - const auto offset = m_worker.GetFrameOffset(); - if( sel == 0 ) - { - ImGui::TextUnformatted( "Tracy initialization" ); - ImGui::Separator(); - TextFocused( "Time:", TimeToString( m_worker.GetFrameTime( *m_frames, sel ) ) ); - } - else if( offset == 0 ) - { - TextDisabledUnformatted( "Frame:" ); - ImGui::SameLine(); - ImGui::TextUnformatted( RealToString( fnum ) ); - ImGui::Separator(); - const auto frameTime = m_worker.GetFrameTime( *m_frames, sel ); - TextFocused( "Frame time:", TimeToString( frameTime ) ); - ImGui::SameLine(); - ImGui::TextDisabled( "(%.1f FPS)", 1000000000.0 / frameTime ); - } - else if( sel == 1 ) - { - ImGui::TextUnformatted( "Missed frames" ); - ImGui::Separator(); - TextFocused( "Time:", TimeToString( m_worker.GetFrameTime( *m_frames, 1 ) ) ); - } - else - { - TextDisabledUnformatted( "Frame:" ); - ImGui::SameLine(); - ImGui::TextUnformatted( RealToString( fnum ) ); - ImGui::Separator(); - const auto frameTime = m_worker.GetFrameTime( *m_frames, sel ); - TextFocused( "Frame time:", TimeToString( frameTime ) ); - ImGui::SameLine(); - ImGui::TextDisabled( "(%.1f FPS)", 1000000000.0 / frameTime ); - } - } - else - { - ImGui::TextDisabled( "%s:", m_worker.GetString( m_frames->name ) ); - ImGui::SameLine(); - ImGui::TextUnformatted( RealToString( fnum ) ); - ImGui::Separator(); - const auto frameTime = m_worker.GetFrameTime( *m_frames, sel ); - TextFocused( "Frame time:", TimeToString( frameTime ) ); - ImGui::SameLine(); - ImGui::TextDisabled( "(%.1f FPS)", 1000000000.0 / frameTime ); - } - } - TextFocused( "Time from start of program:", TimeToStringExact( m_worker.GetFrameBegin( *m_frames, sel ) ) ); - auto fi = m_worker.GetFrameImage( *m_frames, sel ); - if( fi ) - { - if( fi != m_frameTexturePtr ) - { - if( !m_frameTexture ) m_frameTexture = MakeTexture(); - UpdateTexture( m_frameTexture, m_worker.UnpackFrameImage( *fi ), fi->w, fi->h ); - m_frameTexturePtr = fi; - } - ImGui::Separator(); - if( fi->flip ) - { - ImGui::Image( m_frameTexture, ImVec2( fi->w * scale, fi->h * scale ), ImVec2( 0, 1 ), ImVec2( 1, 0 ) ); - } - else - { - ImGui::Image( m_frameTexture, ImVec2( fi->w * scale, fi->h * scale ) ); - } - } - ImGui::EndTooltip(); - - if( io.KeyCtrl ) - { - if( fi && IsMouseDown( 0 ) ) - { - m_showPlayback = true; - m_playback.pause = true; - SetPlaybackFrame( m_frames->frames[sel].frameImage ); - } - } - else - { - if( IsMouseClicked( 0 ) ) - { - m_viewMode = ViewMode::Paused; - m_viewModeHeuristicTry = false; - m_zoomAnim.active = false; - if( !m_playback.pause && m_playback.sync ) m_playback.pause = true; - m_vd.zvStart = m_worker.GetFrameBegin( *m_frames, sel ); - m_vd.zvEnd = m_worker.GetFrameEnd( *m_frames, sel + group - 1 ); - if( m_vd.zvStart == m_vd.zvEnd ) m_vd.zvStart--; - } - else if( IsMouseDragging( 0 ) ) - { - const auto t0 = std::min( m_vd.zvStart, m_worker.GetFrameBegin( *m_frames, sel ) ); - const auto t1 = std::max( m_vd.zvEnd, m_worker.GetFrameEnd( *m_frames, sel + group - 1 ) ); - ZoomToRange( t0, t1 ); - } - } - - if( IsMouseClickReleased( 1 ) ) m_setRangePopup = RangeSlim { m_worker.GetFrameBegin( *m_frames, sel ), m_worker.GetFrameEnd( *m_frames, sel + group - 1 ), true }; - } - - if( ( !m_worker.IsConnected() || m_viewMode == ViewMode::Paused ) && wheel != 0 ) - { - const int pfwidth = GetFrameWidth( prevScale ); - const int pgroup = GetFrameGroup( prevScale ); - - const auto oldoff = mo * pgroup / pfwidth; - m_vd.frameStart = std::min( total, std::max( 0, m_vd.frameStart - int( off - oldoff ) ) ); - } - } - } - - int i = 0, idx = 0; -#ifndef TRACY_NO_STATISTICS - if( m_worker.AreSourceLocationZonesReady() && m_findZone.show && m_findZone.showZoneInFrames && !m_findZone.match.empty() ) - { - auto& zoneData = m_worker.GetZonesForSourceLocation( m_findZone.match[m_findZone.selMatch] ); - zoneData.zones.ensure_sorted(); - auto begin = zoneData.zones.begin(); - while( i < onScreen && m_vd.frameStart + idx < total ) - { - const auto f0 = m_worker.GetFrameBegin( *m_frames, m_vd.frameStart + idx ); - auto f1 = m_worker.GetFrameEnd( *m_frames, m_vd.frameStart + idx ); - auto f = f1 - f0; - if( group > 1 ) - { - const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); - for( int j=1; jEnd() < r; } ); - if( itStart != zoneData.zones.end() ) - { - auto itEnd = std::lower_bound( itStart, zoneData.zones.end(), f1, [] ( const auto& l, const auto& r ) { return l.Zone()->Start() < r; } ); - if( m_frames->continuous ) - { - if( m_findZone.selfTime ) - { - while( itStart != itEnd ) - { - const auto t0 = clamp( itStart->Zone()->Start(), f0, f1 ); - const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), f0, f1 ); - zoneTime += t1 - t0 - GetZoneChildTimeFastClamped( *itStart->Zone(), t0, t1 ); - itStart++; - } - } - else - { - while( itStart != itEnd ) - { - const auto t0 = clamp( itStart->Zone()->Start(), f0, f1 ); - const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), f0, f1 ); - zoneTime += t1 - t0; - itStart++; - } - } - } - else - { - if( m_findZone.selfTime ) - { - while( itStart != itEnd ) - { - const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); - for( int j=0; jZone()->Start(), ft0, ft1 ); - const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), ft0, ft1 ); - zoneTime += t1 - t0 - GetZoneChildTimeFastClamped( *itStart->Zone(), t0, t1 ); - } - itStart++; - } - } - else - { - while( itStart != itEnd ) - { - const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); - for( int j=0; jZone()->Start(), ft0, ft1 ); - const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), ft0, ft1 ); - zoneTime += t1 - t0; - } - itStart++; - } - } - } - } - else - { - begin = itStart; - } - - zoneTime /= group; - const auto h = std::max( 1.f, float( std::min( MaxFrameTime, f ) ) / MaxFrameTime * ( Height - 2 ) ); - if( zoneTime == 0 ) - { - if( fwidth != 1 ) - { - draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), 0xFF888888 ); - } - else - { - DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), 0xFF888888 ); - } - } - else if( zoneTime <= f ) - { - const auto zh = float( std::min( MaxFrameTime, zoneTime ) ) / MaxFrameTime * ( Height - 2 ); - if( fwidth != 1 ) - { - draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1-zh ), 0xFF888888 ); - draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-zh ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), 0xFFEEEEEE ); - } - else - { - DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2-zh ), 0xFF888888 ); - DrawLine( draw, dpos + ImVec2( 1+i, Height-2-zh ), dpos + ImVec2( 1+i, Height-2 ), 0xFFEEEEEE ); - } - } - else - { - const auto zh = float( std::min( MaxFrameTime, zoneTime ) ) / MaxFrameTime * ( Height - 2 ); - if( fwidth != 1 ) - { - draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-zh ), wpos + ImVec2( fwidth + i*fwidth, Height-1-h ), 0xFF2222BB ); - draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), 0xFFEEEEEE ); - } - else - { - DrawLine( draw, dpos + ImVec2( 1+i, Height-2-zh ), dpos + ImVec2( 1+i, Height-2-h ), 0xFF2222BB ); - DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), 0xFFEEEEEE ); - } - } - - i++; - idx += group; - } - } - else -#endif - { - while( i < onScreen && m_vd.frameStart + idx < total ) - { - auto f = m_worker.GetFrameTime( *m_frames, m_vd.frameStart + idx ); - if( group > 1 ) - { - const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); - for( int j=1; j( MaxFrameTime, f ) ) / MaxFrameTime * ( Height - 2 ) ); - if( fwidth != 1 ) - { - draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), GetFrameColor( f ) ); - } - else - { - DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), GetFrameColor( f ) ); - } - - i++; - idx += group; - } - } - - const auto zrange = m_worker.GetFrameRange( *m_frames, m_vd.zvStart, m_vd.zvEnd ); - if( zrange.second > m_vd.frameStart && zrange.first < m_vd.frameStart + onScreen * group ) - { - auto x1 = std::min( onScreen * fwidth, ( zrange.second - m_vd.frameStart ) * fwidth / group ); - auto x0 = std::max( 0, ( zrange.first - m_vd.frameStart ) * fwidth / group ); - - if( x0 == x1 ) x1 = x0 + 1; - if( x1 - x0 >= 3 ) - { - draw->AddRectFilled( wpos + ImVec2( 2+x0, 0 ), wpos + ImVec2( x1, Height ), 0x55DD22DD ); - DrawLine( draw, dpos + ImVec2( 1+x0, -1 ), dpos + ImVec2( 1+x0, Height-1 ), 0x55FF55FF ); - DrawLine( draw, dpos + ImVec2( x1, -1 ), dpos + ImVec2( x1, Height-1 ), 0x55FF55FF ); - } - else - { - draw->AddRectFilled( wpos + ImVec2( 1+x0, 0 ), wpos + ImVec2( 1+x1, Height ), 0x55FF55FF ); - } - } - - DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * BadTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * BadTime / MaxFrameTime ) ), 0x4422DDDD ); - DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * GoodTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * GoodTime / MaxFrameTime ) ), 0x4422DD22 ); - DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * BestTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * BestTime / MaxFrameTime ) ), 0x44DD9900 ); -} - void View::HandleRange( Range& range, int64_t timespan, const ImVec2& wpos, float w ) { if( !IsMouseDown( 0 ) ) range.modMin = range.modMax = false; diff --git a/server/TracyView_FrameOverview.cpp b/server/TracyView_FrameOverview.cpp new file mode 100644 index 00000000..0e5d65f6 --- /dev/null +++ b/server/TracyView_FrameOverview.cpp @@ -0,0 +1,453 @@ +#include "TracyMouse.hpp" +#include "TracyPrint.hpp" +#include "TracyView.hpp" + +namespace tracy +{ + +enum { BestTime = 1000 * 1000 * 1000 / 143 }; +enum { GoodTime = 1000 * 1000 * 1000 / 59 }; +enum { BadTime = 1000 * 1000 * 1000 / 29 }; + +static ImU32 GetFrameColor( uint64_t frameTime ) +{ + return frameTime > BadTime ? 0xFF2222DD : + frameTime > GoodTime ? 0xFF22DDDD : + frameTime > BestTime ? 0xFF22DD22 : 0xFFDD9900; +} + +static int GetFrameWidth( int frameScale ) +{ + return frameScale == 0 ? 4 : ( frameScale < 0 ? 6 : 1 ); +} + +static int GetFrameGroup( int frameScale ) +{ + return frameScale < 2 ? 1 : ( 1 << ( frameScale - 1 ) ); +} + +template +constexpr const T& clamp( const T& v, const T& lo, const T& hi ) +{ + return v < lo ? lo : v > hi ? hi : v; +} + +void View::DrawFrames() +{ + assert( m_worker.GetFrameCount( *m_frames ) != 0 ); + + const auto scale = GetScale(); + const auto Height = 50 * scale; + + enum { MaxFrameTime = 50 * 1000 * 1000 }; // 50ms + + ImGuiWindow* window = ImGui::GetCurrentWindowRead(); + if( window->SkipItems ) return; + + auto& io = ImGui::GetIO(); + + const auto wpos = ImGui::GetCursorScreenPos(); + const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); + const auto wspace = ImGui::GetWindowContentRegionMax() - ImGui::GetWindowContentRegionMin(); + const auto w = wspace.x; + auto draw = ImGui::GetWindowDrawList(); + + ImGui::InvisibleButton( "##frames", ImVec2( w, Height ) ); + bool hover = ImGui::IsItemHovered(); + + draw->AddRectFilled( wpos, wpos + ImVec2( w, Height ), 0x33FFFFFF ); + const auto wheel = io.MouseWheel; + const auto prevScale = m_vd.frameScale; + if( hover ) + { + if( wheel > 0 ) + { + if( m_vd.frameScale >= 0 ) m_vd.frameScale--; + } + else if( wheel < 0 ) + { + if( m_vd.frameScale < 10 ) m_vd.frameScale++; + } + } + + const int fwidth = GetFrameWidth( m_vd.frameScale ); + const int group = GetFrameGroup( m_vd.frameScale ); + const int total = m_worker.GetFrameCount( *m_frames ); + const int onScreen = ( w - 2 ) / fwidth; + if( m_viewMode != ViewMode::Paused ) + { + m_vd.frameStart = ( total < onScreen * group ) ? 0 : total - onScreen * group; + if( m_viewMode == ViewMode::LastFrames ) + { + SetViewToLastFrames(); + } + else + { + assert( m_viewMode == ViewMode::LastRange ); + const auto delta = m_worker.GetLastTime() - m_vd.zvEnd; + if( delta != 0 ) + { + m_vd.zvStart += delta; + m_vd.zvEnd += delta; + } + } + } + + if( hover ) + { + const auto hwheel_delta = io.MouseWheelH * 100.f; + if( IsMouseDragging( 1 ) || hwheel_delta != 0 ) + { + m_viewMode = ViewMode::Paused; + m_viewModeHeuristicTry = false; + auto delta = GetMouseDragDelta( 1 ).x; + if( delta == 0 ) delta = hwheel_delta; + if( abs( delta ) >= fwidth ) + { + const auto d = (int)delta / fwidth; + m_vd.frameStart = std::max( 0, m_vd.frameStart - d * group ); + io.MouseClickedPos[1].x = io.MousePos.x + d * fwidth - delta; + } + } + + const auto mx = io.MousePos.x; + if( mx > wpos.x && mx < wpos.x + w - 1 ) + { + const auto mo = mx - ( wpos.x + 1 ); + const auto off = mo * group / fwidth; + + const int sel = m_vd.frameStart + off; + if( sel < total ) + { + ImGui::BeginTooltip(); + if( group > 1 ) + { + auto f = m_worker.GetFrameTime( *m_frames, sel ); + auto g = std::min( group, total - sel ); + for( int j=1; jname == 0 ) + { + const auto offset = m_worker.GetFrameOffset(); + if( sel == 0 ) + { + ImGui::TextUnformatted( "Tracy initialization" ); + ImGui::Separator(); + TextFocused( "Time:", TimeToString( m_worker.GetFrameTime( *m_frames, sel ) ) ); + } + else if( offset == 0 ) + { + TextDisabledUnformatted( "Frame:" ); + ImGui::SameLine(); + ImGui::TextUnformatted( RealToString( fnum ) ); + ImGui::Separator(); + const auto frameTime = m_worker.GetFrameTime( *m_frames, sel ); + TextFocused( "Frame time:", TimeToString( frameTime ) ); + ImGui::SameLine(); + ImGui::TextDisabled( "(%.1f FPS)", 1000000000.0 / frameTime ); + } + else if( sel == 1 ) + { + ImGui::TextUnformatted( "Missed frames" ); + ImGui::Separator(); + TextFocused( "Time:", TimeToString( m_worker.GetFrameTime( *m_frames, 1 ) ) ); + } + else + { + TextDisabledUnformatted( "Frame:" ); + ImGui::SameLine(); + ImGui::TextUnformatted( RealToString( fnum ) ); + ImGui::Separator(); + const auto frameTime = m_worker.GetFrameTime( *m_frames, sel ); + TextFocused( "Frame time:", TimeToString( frameTime ) ); + ImGui::SameLine(); + ImGui::TextDisabled( "(%.1f FPS)", 1000000000.0 / frameTime ); + } + } + else + { + ImGui::TextDisabled( "%s:", m_worker.GetString( m_frames->name ) ); + ImGui::SameLine(); + ImGui::TextUnformatted( RealToString( fnum ) ); + ImGui::Separator(); + const auto frameTime = m_worker.GetFrameTime( *m_frames, sel ); + TextFocused( "Frame time:", TimeToString( frameTime ) ); + ImGui::SameLine(); + ImGui::TextDisabled( "(%.1f FPS)", 1000000000.0 / frameTime ); + } + } + TextFocused( "Time from start of program:", TimeToStringExact( m_worker.GetFrameBegin( *m_frames, sel ) ) ); + auto fi = m_worker.GetFrameImage( *m_frames, sel ); + if( fi ) + { + if( fi != m_frameTexturePtr ) + { + if( !m_frameTexture ) m_frameTexture = MakeTexture(); + UpdateTexture( m_frameTexture, m_worker.UnpackFrameImage( *fi ), fi->w, fi->h ); + m_frameTexturePtr = fi; + } + ImGui::Separator(); + if( fi->flip ) + { + ImGui::Image( m_frameTexture, ImVec2( fi->w * scale, fi->h * scale ), ImVec2( 0, 1 ), ImVec2( 1, 0 ) ); + } + else + { + ImGui::Image( m_frameTexture, ImVec2( fi->w * scale, fi->h * scale ) ); + } + } + ImGui::EndTooltip(); + + if( io.KeyCtrl ) + { + if( fi && IsMouseDown( 0 ) ) + { + m_showPlayback = true; + m_playback.pause = true; + SetPlaybackFrame( m_frames->frames[sel].frameImage ); + } + } + else + { + if( IsMouseClicked( 0 ) ) + { + m_viewMode = ViewMode::Paused; + m_viewModeHeuristicTry = false; + m_zoomAnim.active = false; + if( !m_playback.pause && m_playback.sync ) m_playback.pause = true; + m_vd.zvStart = m_worker.GetFrameBegin( *m_frames, sel ); + m_vd.zvEnd = m_worker.GetFrameEnd( *m_frames, sel + group - 1 ); + if( m_vd.zvStart == m_vd.zvEnd ) m_vd.zvStart--; + } + else if( IsMouseDragging( 0 ) ) + { + const auto t0 = std::min( m_vd.zvStart, m_worker.GetFrameBegin( *m_frames, sel ) ); + const auto t1 = std::max( m_vd.zvEnd, m_worker.GetFrameEnd( *m_frames, sel + group - 1 ) ); + ZoomToRange( t0, t1 ); + } + } + + if( IsMouseClickReleased( 1 ) ) m_setRangePopup = RangeSlim { m_worker.GetFrameBegin( *m_frames, sel ), m_worker.GetFrameEnd( *m_frames, sel + group - 1 ), true }; + } + + if( ( !m_worker.IsConnected() || m_viewMode == ViewMode::Paused ) && wheel != 0 ) + { + const int pfwidth = GetFrameWidth( prevScale ); + const int pgroup = GetFrameGroup( prevScale ); + + const auto oldoff = mo * pgroup / pfwidth; + m_vd.frameStart = std::min( total, std::max( 0, m_vd.frameStart - int( off - oldoff ) ) ); + } + } + } + + int i = 0, idx = 0; +#ifndef TRACY_NO_STATISTICS + if( m_worker.AreSourceLocationZonesReady() && m_findZone.show && m_findZone.showZoneInFrames && !m_findZone.match.empty() ) + { + auto& zoneData = m_worker.GetZonesForSourceLocation( m_findZone.match[m_findZone.selMatch] ); + zoneData.zones.ensure_sorted(); + auto begin = zoneData.zones.begin(); + while( i < onScreen && m_vd.frameStart + idx < total ) + { + const auto f0 = m_worker.GetFrameBegin( *m_frames, m_vd.frameStart + idx ); + auto f1 = m_worker.GetFrameEnd( *m_frames, m_vd.frameStart + idx ); + auto f = f1 - f0; + if( group > 1 ) + { + const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); + for( int j=1; jEnd() < r; } ); + if( itStart != zoneData.zones.end() ) + { + auto itEnd = std::lower_bound( itStart, zoneData.zones.end(), f1, [] ( const auto& l, const auto& r ) { return l.Zone()->Start() < r; } ); + if( m_frames->continuous ) + { + if( m_findZone.selfTime ) + { + while( itStart != itEnd ) + { + const auto t0 = clamp( itStart->Zone()->Start(), f0, f1 ); + const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), f0, f1 ); + zoneTime += t1 - t0 - GetZoneChildTimeFastClamped( *itStart->Zone(), t0, t1 ); + itStart++; + } + } + else + { + while( itStart != itEnd ) + { + const auto t0 = clamp( itStart->Zone()->Start(), f0, f1 ); + const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), f0, f1 ); + zoneTime += t1 - t0; + itStart++; + } + } + } + else + { + if( m_findZone.selfTime ) + { + while( itStart != itEnd ) + { + const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); + for( int j=0; jZone()->Start(), ft0, ft1 ); + const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), ft0, ft1 ); + zoneTime += t1 - t0 - GetZoneChildTimeFastClamped( *itStart->Zone(), t0, t1 ); + } + itStart++; + } + } + else + { + while( itStart != itEnd ) + { + const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); + for( int j=0; jZone()->Start(), ft0, ft1 ); + const auto t1 = clamp( m_worker.GetZoneEndDirect( *itStart->Zone() ), ft0, ft1 ); + zoneTime += t1 - t0; + } + itStart++; + } + } + } + } + else + { + begin = itStart; + } + + zoneTime /= group; + const auto h = std::max( 1.f, float( std::min( MaxFrameTime, f ) ) / MaxFrameTime * ( Height - 2 ) ); + if( zoneTime == 0 ) + { + if( fwidth != 1 ) + { + draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), 0xFF888888 ); + } + else + { + DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), 0xFF888888 ); + } + } + else if( zoneTime <= f ) + { + const auto zh = float( std::min( MaxFrameTime, zoneTime ) ) / MaxFrameTime * ( Height - 2 ); + if( fwidth != 1 ) + { + draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1-zh ), 0xFF888888 ); + draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-zh ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), 0xFFEEEEEE ); + } + else + { + DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2-zh ), 0xFF888888 ); + DrawLine( draw, dpos + ImVec2( 1+i, Height-2-zh ), dpos + ImVec2( 1+i, Height-2 ), 0xFFEEEEEE ); + } + } + else + { + const auto zh = float( std::min( MaxFrameTime, zoneTime ) ) / MaxFrameTime * ( Height - 2 ); + if( fwidth != 1 ) + { + draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-zh ), wpos + ImVec2( fwidth + i*fwidth, Height-1-h ), 0xFF2222BB ); + draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), 0xFFEEEEEE ); + } + else + { + DrawLine( draw, dpos + ImVec2( 1+i, Height-2-zh ), dpos + ImVec2( 1+i, Height-2-h ), 0xFF2222BB ); + DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), 0xFFEEEEEE ); + } + } + + i++; + idx += group; + } + } + else +#endif + { + while( i < onScreen && m_vd.frameStart + idx < total ) + { + auto f = m_worker.GetFrameTime( *m_frames, m_vd.frameStart + idx ); + if( group > 1 ) + { + const int g = std::min( group, total - ( m_vd.frameStart + idx ) ); + for( int j=1; j( MaxFrameTime, f ) ) / MaxFrameTime * ( Height - 2 ) ); + if( fwidth != 1 ) + { + draw->AddRectFilled( wpos + ImVec2( 1 + i*fwidth, Height-1-h ), wpos + ImVec2( fwidth + i*fwidth, Height-1 ), GetFrameColor( f ) ); + } + else + { + DrawLine( draw, dpos + ImVec2( 1+i, Height-2-h ), dpos + ImVec2( 1+i, Height-2 ), GetFrameColor( f ) ); + } + + i++; + idx += group; + } + } + + const auto zrange = m_worker.GetFrameRange( *m_frames, m_vd.zvStart, m_vd.zvEnd ); + if( zrange.second > m_vd.frameStart && zrange.first < m_vd.frameStart + onScreen * group ) + { + auto x1 = std::min( onScreen * fwidth, ( zrange.second - m_vd.frameStart ) * fwidth / group ); + auto x0 = std::max( 0, ( zrange.first - m_vd.frameStart ) * fwidth / group ); + + if( x0 == x1 ) x1 = x0 + 1; + if( x1 - x0 >= 3 ) + { + draw->AddRectFilled( wpos + ImVec2( 2+x0, 0 ), wpos + ImVec2( x1, Height ), 0x55DD22DD ); + DrawLine( draw, dpos + ImVec2( 1+x0, -1 ), dpos + ImVec2( 1+x0, Height-1 ), 0x55FF55FF ); + DrawLine( draw, dpos + ImVec2( x1, -1 ), dpos + ImVec2( x1, Height-1 ), 0x55FF55FF ); + } + else + { + draw->AddRectFilled( wpos + ImVec2( 1+x0, 0 ), wpos + ImVec2( 1+x1, Height ), 0x55FF55FF ); + } + } + + DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * BadTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * BadTime / MaxFrameTime ) ), 0x4422DDDD ); + DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * GoodTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * GoodTime / MaxFrameTime ) ), 0x4422DD22 ); + DrawLine( draw, dpos + ImVec2( 0, round( Height - Height * BestTime / MaxFrameTime ) ), dpos + ImVec2( w, round( Height - Height * BestTime / MaxFrameTime ) ), 0x44DD9900 ); +} + +}