diff --git a/profiler/build/win32/Tracy.vcxproj b/profiler/build/win32/Tracy.vcxproj
index 449381d5..d582aa87 100644
--- a/profiler/build/win32/Tracy.vcxproj
+++ b/profiler/build/win32/Tracy.vcxproj
@@ -138,6 +138,7 @@
+
@@ -153,6 +154,7 @@
+
@@ -277,6 +279,7 @@
+
diff --git a/profiler/build/win32/Tracy.vcxproj.filters b/profiler/build/win32/Tracy.vcxproj.filters
index 591fd453..c362dd55 100644
--- a/profiler/build/win32/Tracy.vcxproj.filters
+++ b/profiler/build/win32/Tracy.vcxproj.filters
@@ -366,6 +366,12 @@
server
+
+ server
+
+
+ server
+
@@ -743,6 +749,9 @@
server
+
+ server
+
diff --git a/server/TracyTimelineItemGpu.cpp b/server/TracyTimelineItemGpu.cpp
new file mode 100644
index 00000000..52924b5c
--- /dev/null
+++ b/server/TracyTimelineItemGpu.cpp
@@ -0,0 +1,195 @@
+#include "TracyImGui.hpp"
+#include "TracyPopcnt.hpp"
+#include "TracyPrint.hpp"
+#include "TracyTimelineItemGpu.hpp"
+#include "TracyUtility.hpp"
+#include "TracyView.hpp"
+#include "TracyWorker.hpp"
+
+namespace tracy
+{
+
+TimelineItemGpu::TimelineItemGpu( View& view, Worker& worker, GpuCtxData* gpu )
+ : TimelineItem( view, worker )
+ , m_gpu( gpu )
+ , m_idx( view.GetNextGpuIdx() )
+{
+}
+
+bool TimelineItemGpu::IsEmpty() const
+{
+ return m_gpu->threadData.empty();
+}
+
+const char* TimelineItemGpu::HeaderLabel() const
+{
+ static char buf[4096];
+ if( m_gpu->name.Active() )
+ {
+ sprintf( buf, "%s context %i: %s", GpuContextNames[(int)m_gpu->type], m_idx, m_worker.GetString( m_gpu->name ) );
+ }
+ else
+ {
+ sprintf( buf, "%s context %i", GpuContextNames[(int)m_gpu->type], m_idx );
+ }
+ return buf;
+}
+
+void TimelineItemGpu::HeaderTooltip( const char* label ) const
+{
+ const bool dynamicColors = m_view.GetViewData().dynamicColors;
+ const bool isMultithreaded =
+ ( m_gpu->type == GpuContextType::Vulkan ) ||
+ ( m_gpu->type == GpuContextType::OpenCL ) ||
+ ( m_gpu->type == GpuContextType::Direct3D12 );
+
+ char buf[64];
+ sprintf( buf, "%s context %i", GpuContextNames[(int)m_gpu->type], m_idx );
+
+ ImGui::BeginTooltip();
+ ImGui::TextUnformatted( buf );
+ if( m_gpu->name.Active() ) TextFocused( "Name:", m_worker.GetString( m_gpu->name ) );
+ ImGui::Separator();
+ if( !isMultithreaded )
+ {
+ SmallColorBox( GetThreadColor( m_gpu->thread, 0, dynamicColors ) );
+ ImGui::SameLine();
+ TextFocused( "Thread:", m_worker.GetThreadName( m_gpu->thread ) );
+ }
+ else
+ {
+ if( m_gpu->threadData.size() == 1 )
+ {
+ auto it = m_gpu->threadData.begin();
+ auto tid = it->first;
+ if( tid == 0 )
+ {
+ if( !it->second.timeline.empty() )
+ {
+ if( it->second.timeline.is_magic() )
+ {
+ auto& tl = *(Vector*)&it->second.timeline;
+ tid = m_worker.DecompressThread( tl.begin()->Thread() );
+ }
+ else
+ {
+ tid = m_worker.DecompressThread( (*it->second.timeline.begin())->Thread() );
+ }
+ }
+ }
+ SmallColorBox( GetThreadColor( tid, 0, dynamicColors ) );
+ ImGui::SameLine();
+ TextFocused( "Thread:", m_worker.GetThreadName( tid ) );
+ ImGui::SameLine();
+ ImGui::TextDisabled( "(%s)", RealToString( tid ) );
+ if( m_worker.IsThreadFiber( tid ) )
+ {
+ ImGui::SameLine();
+ TextColoredUnformatted( ImVec4( 0.2f, 0.6f, 0.2f, 1.f ), "Fiber" );
+ }
+ }
+ else
+ {
+ ImGui::TextDisabled( "Threads:" );
+ ImGui::Indent();
+ for( auto& td : m_gpu->threadData )
+ {
+ SmallColorBox( GetThreadColor( td.first, 0, dynamicColors ) );
+ ImGui::SameLine();
+ ImGui::TextUnformatted( m_worker.GetThreadName( td.first ) );
+ ImGui::SameLine();
+ ImGui::TextDisabled( "(%s)", RealToString( td.first ) );
+ }
+ ImGui::Unindent();
+ }
+ }
+ const auto t0 = RangeBegin();
+ if( t0 != std::numeric_limits::max() )
+ {
+ TextFocused( "Appeared at", TimeToString( t0 ) );
+ }
+ TextFocused( "Zone count:", RealToString( m_gpu->count ) );
+ if( m_gpu->period != 1.f )
+ {
+ TextFocused( "Timestamp accuracy:", TimeToString( m_gpu->period ) );
+ }
+ if( m_gpu->overflow != 0 )
+ {
+ ImGui::Separator();
+ ImGui::TextUnformatted( "GPU timer overflow has been detected." );
+ TextFocused( "Timer resolution:", RealToString( 63 - TracyLzcnt( m_gpu->overflow ) ) );
+ ImGui::SameLine();
+ TextDisabledUnformatted( "bits" );
+ }
+ ImGui::EndTooltip();
+}
+
+void TimelineItemGpu::HeaderExtraContents( int offset, const ImVec2& wpos, float labelWidth, double pxns, bool hover )
+{
+ auto draw = ImGui::GetWindowDrawList();
+ const auto ty = ImGui::GetTextLineHeight();
+
+ /*
+ char tmp[128];
+ sprintf( tmp, "(y-range: %s, visible data points: %s)", FormatPlotValue( m_plot->rMax - m_plot->rMin, m_plot->format ), RealToString( m_plot->num ) );
+ draw->AddText( wpos + ImVec2( ty * 1.5f + labelWidth, offset ), 0xFF226E6E, tmp );
+ */
+}
+
+int64_t TimelineItemGpu::RangeBegin() const
+{
+ int64_t t = std::numeric_limits::max();
+ for( auto& td : m_gpu->threadData )
+ {
+ int64_t t0;
+ if( td.second.timeline.is_magic() )
+ {
+ t0 = ((Vector*)&td.second.timeline)->front().GpuStart();
+ }
+ else
+ {
+ t0 = td.second.timeline.front()->GpuStart();
+ }
+ if( t0 >= 0 )
+ {
+ t = std::min( t, t0 );
+ }
+ }
+ return t;
+}
+
+int64_t TimelineItemGpu::RangeEnd() const
+{
+ int64_t t = std::numeric_limits::min();
+ for( auto& td : m_gpu->threadData )
+ {
+ int64_t t0;
+ if( td.second.timeline.is_magic() )
+ {
+ t0 = ((Vector*)&td.second.timeline)->front().GpuStart();
+ }
+ else
+ {
+ t0 = td.second.timeline.front()->GpuStart();
+ }
+ if( t0 >= 0 )
+ {
+ if( td.second.timeline.is_magic() )
+ {
+ t = std::max( t, std::min( m_worker.GetLastTime(), m_worker.GetZoneEnd( ((Vector*)&td.second.timeline)->back() ) ) );
+ }
+ else
+ {
+ t = std::max( t, std::min( m_worker.GetLastTime(), m_worker.GetZoneEnd( *td.second.timeline.back() ) ) );
+ }
+ }
+ }
+ return t;
+}
+
+bool TimelineItemGpu::DrawContents( double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax )
+{
+ return m_view.DrawGpu( *m_gpu, pxns, offset, wpos, hover, yMin, yMax );
+}
+
+}
diff --git a/server/TracyTimelineItemGpu.hpp b/server/TracyTimelineItemGpu.hpp
new file mode 100644
index 00000000..e538ccf3
--- /dev/null
+++ b/server/TracyTimelineItemGpu.hpp
@@ -0,0 +1,38 @@
+#ifndef __TRACYTIMELINEITEMGPU_HPP__
+#define __TRACYTIMELINEITEMGPU_HPP__
+
+#include "TracyEvent.hpp"
+#include "TracyTimelineItem.hpp"
+
+namespace tracy
+{
+
+class TimelineItemGpu final : public TimelineItem
+{
+public:
+ TimelineItemGpu( View& view, Worker& worker, GpuCtxData* gpu );
+
+protected:
+ uint32_t HeaderColor() const override { return 0xFFFFAAAA; }
+ uint32_t HeaderColorInactive() const override { return 0xFF886666; }
+ uint32_t HeaderLineColor() const override { return 0x33FFFFFF; }
+ const char* HeaderLabel() const override;
+
+ int64_t RangeBegin() const override;
+ int64_t RangeEnd() const override;
+
+ void HeaderTooltip( const char* label ) const override;
+ void HeaderExtraContents( int offset, const ImVec2& wpos, float labelWidth, double pxns, bool hover ) override;
+
+ bool DrawContents( double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax ) override;
+
+ bool IsEmpty() const override;
+
+private:
+ GpuCtxData* m_gpu;
+ int m_idx;
+};
+
+}
+
+#endif
diff --git a/server/TracyView.hpp b/server/TracyView.hpp
index ce4788c0..e8a48d1a 100644
--- a/server/TracyView.hpp
+++ b/server/TracyView.hpp
@@ -120,6 +120,7 @@ public:
bool DrawThread( const ThreadData& thread, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax, bool ghostMode );
void DrawThreadMessages( const ThreadData& thread, double pxns, int offset, const ImVec2& wpos, bool hover );
void DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const ImVec2& dr );
+ bool DrawGpu( const GpuCtxData& gpu, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax );
bool m_showRanges = false;
Range m_statRange;
diff --git a/server/TracyView_GpuTimeline.cpp b/server/TracyView_GpuTimeline.cpp
new file mode 100644
index 00000000..677a0174
--- /dev/null
+++ b/server/TracyView_GpuTimeline.cpp
@@ -0,0 +1,354 @@
+#include "TracyColor.hpp"
+#include "TracyImGui.hpp"
+#include "TracyMouse.hpp"
+#include "TracyPrint.hpp"
+#include "TracyView.hpp"
+
+namespace tracy
+{
+
+constexpr float MinVisSize = 3;
+
+bool View::DrawGpu( const GpuCtxData& gpu, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax )
+{
+ const auto w = ImGui::GetContentRegionAvail().x - 1;
+ const auto ty = ImGui::GetTextLineHeight();
+ const auto ostep = ty + 1;
+ const auto nspx = 1.0 / pxns;
+ auto draw = ImGui::GetWindowDrawList();
+ const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
+
+ ImGui::PushFont( m_smallFont );
+ const auto sty = ImGui::GetTextLineHeight();
+ const auto sstep = sty + 1;
+ ImGui::PopFont();
+
+ const auto singleThread = gpu.threadData.size() == 1;
+ int depth = 0;
+
+ for( auto& td : gpu.threadData )
+ {
+ auto& tl = td.second.timeline;
+ assert( !tl.empty() );
+ if( tl.is_magic() )
+ {
+ auto& tlm = *(Vector*)&tl;
+ if( tlm.front().GpuStart() >= 0 )
+ {
+ const auto begin = tlm.front().GpuStart();
+ const auto drift = GpuDrift( &gpu );
+ if( !singleThread ) offset += sstep;
+ const auto partDepth = DispatchGpuZoneLevel( tl, hover, pxns, int64_t( nspx ), wpos, offset, 0, gpu.thread, yMin, yMax, begin, drift );
+ if( partDepth != 0 )
+ {
+ if( !singleThread )
+ {
+ ImGui::PushFont( m_smallFont );
+ DrawTextContrast( draw, wpos + ImVec2( ty, offset-1-sstep ), 0xFFFFAAAA, m_worker.GetThreadName( td.first ) );
+ DrawLine( draw, dpos + ImVec2( 0, offset+sty-sstep ), dpos + ImVec2( w, offset+sty-sstep ), 0x22FFAAAA );
+ ImGui::PopFont();
+ }
+
+ offset += ostep * partDepth;
+ depth += partDepth;
+ }
+ else if( !singleThread )
+ {
+ offset -= sstep;
+ }
+ }
+ }
+ else
+ {
+ if( tl.front()->GpuStart() >= 0 )
+ {
+ const auto begin = tl.front()->GpuStart();
+ const auto drift = GpuDrift( &gpu );
+ if( !singleThread ) offset += sstep;
+ const auto partDepth = DispatchGpuZoneLevel( tl, hover, pxns, int64_t( nspx ), wpos, offset, 0, gpu.thread, yMin, yMax, begin, drift );
+ if( partDepth != 0 )
+ {
+ if( !singleThread )
+ {
+ ImGui::PushFont( m_smallFont );
+ DrawTextContrast( draw, wpos + ImVec2( ty, offset-1-sstep ), 0xFFFFAAAA, m_worker.GetThreadName( td.first ) );
+ DrawLine( draw, dpos + ImVec2( 0, offset+sty-sstep ), dpos + ImVec2( w, offset+sty-sstep ), 0x22FFAAAA );
+ ImGui::PopFont();
+ }
+
+ offset += ostep * partDepth;
+ depth += partDepth;
+ }
+ else if( !singleThread )
+ {
+ offset -= sstep;
+ }
+ }
+ }
+ }
+ return depth != 0;
+}
+
+int View::DispatchGpuZoneLevel( const Vector>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift )
+{
+ const auto ty = ImGui::GetTextLineHeight();
+ const auto ostep = ty + 1;
+ const auto offset = _offset + ostep * depth;
+
+ const auto yPos = wpos.y + offset;
+ if( yPos + ostep >= yMin && yPos <= yMax )
+ {
+ if( vec.is_magic() )
+ {
+ return DrawGpuZoneLevel>( *(Vector*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
+ }
+ else
+ {
+ return DrawGpuZoneLevel>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
+ }
+ }
+ else
+ {
+ if( vec.is_magic() )
+ {
+ return SkipGpuZoneLevel>( *(Vector*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
+ }
+ else
+ {
+ return SkipGpuZoneLevel>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
+ }
+ }
+}
+
+template
+int View::DrawGpuZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift )
+{
+ const auto delay = m_worker.GetDelay();
+ const auto resolution = m_worker.GetResolution();
+ // cast to uint64_t, so that unended zones (end = -1) are still drawn
+ auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - delay ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
+ if( it == vec.end() ) return depth;
+
+ const auto zitend = std::lower_bound( it, vec.end(), std::max( 0, m_vd.zvEnd + resolution ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuStart(), begin, drift ) < (uint64_t)r; } );
+ if( it == zitend ) return depth;
+
+ const auto w = ImGui::GetContentRegionAvail().x - 1;
+ const auto ty = ImGui::GetTextLineHeight();
+ const auto ostep = ty + 1;
+ const auto offset = _offset + ostep * depth;
+ auto draw = ImGui::GetWindowDrawList();
+ const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
+
+ depth++;
+ int maxdepth = depth;
+
+ Adapter a;
+ while( it < zitend )
+ {
+ auto& ev = a(*it);
+ auto end = m_worker.GetZoneEnd( ev );
+ if( end == std::numeric_limits::max() ) break;
+ const auto start = AdjustGpuTime( ev.GpuStart(), begin, drift );
+ end = AdjustGpuTime( end, begin, drift );
+ const auto zsz = std::max( ( end - start ) * pxns, pxns * 0.5 );
+ if( zsz < MinVisSize )
+ {
+ const auto color = GetZoneColor( ev );
+ const auto MinVisNs = MinVisSize * nspx;
+ int num = 0;
+ const auto px0 = ( start - m_vd.zvStart ) * pxns;
+ auto px1ns = end - m_vd.zvStart;
+ auto rend = end;
+ auto nextTime = end + MinVisNs;
+ for(;;)
+ {
+ const auto prevIt = it;
+ it = std::lower_bound( it, zitend, std::max( 0, nextTime ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
+ if( it == prevIt ) ++it;
+ num += std::distance( prevIt, it );
+ if( it == zitend ) break;
+ const auto nend = AdjustGpuTime( m_worker.GetZoneEnd( a(*it) ), begin, drift );
+ const auto nsnext = nend - m_vd.zvStart;
+ if( nsnext < 0 || nsnext - px1ns >= MinVisNs * 2 ) break;
+ px1ns = nsnext;
+ rend = nend;
+ nextTime = nend + nspx;
+ }
+ const auto px1 = px1ns * pxns;
+ draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ), color );
+ DrawZigZag( draw, wpos + ImVec2( 0, offset + ty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), ty/4, DarkenColor( color ) );
+ if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty + 1 ) ) )
+ {
+ if( num > 1 )
+ {
+ ImGui::BeginTooltip();
+ TextFocused( "Zones too small to display:", RealToString( num ) );
+ ImGui::Separator();
+ TextFocused( "Execution time:", TimeToString( rend - start ) );
+ ImGui::EndTooltip();
+
+ if( IsMouseClicked( 2 ) && rend - start > 0 )
+ {
+ ZoomToRange( start, rend );
+ }
+ }
+ else
+ {
+ const auto zoneThread = thread != 0 ? thread : m_worker.DecompressThread( ev.Thread() );
+ ZoneTooltip( ev );
+
+ if( IsMouseClicked( 2 ) && rend - start > 0 )
+ {
+ ZoomToZone( ev );
+ }
+ if( IsMouseClicked( 0 ) )
+ {
+ ShowZoneInfo( ev, zoneThread );
+ }
+
+ m_gpuThread = zoneThread;
+ m_gpuStart = ev.CpuStart();
+ m_gpuEnd = ev.CpuEnd();
+ }
+ }
+ const auto tmp = RealToString( num );
+ const auto tsz = ImGui::CalcTextSize( tmp );
+ if( tsz.x < px1 - px0 )
+ {
+ const auto x = px0 + ( px1 - px0 - tsz.x ) / 2;
+ DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFF4488DD, tmp );
+ }
+ }
+ else
+ {
+ if( ev.Child() >= 0 )
+ {
+ const auto d = DispatchGpuZoneLevel( m_worker.GetGpuChildren( ev.Child() ), hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
+ if( d > maxdepth ) maxdepth = d;
+ }
+
+ const char* zoneName = m_worker.GetZoneName( ev );
+ auto tsz = ImGui::CalcTextSize( zoneName );
+
+ const auto pr0 = ( start - m_vd.zvStart ) * pxns;
+ const auto pr1 = ( end - m_vd.zvStart ) * pxns;
+ const auto px0 = std::max( pr0, -10.0 );
+ const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } );
+ const auto zoneColor = GetZoneColorData( ev );
+ draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.color );
+ if( zoneColor.highlight )
+ {
+ draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.accentColor, 0.f, -1, zoneColor.thickness );
+ }
+ else
+ {
+ const auto darkColor = DarkenColor( zoneColor.color );
+ DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px0, offset ), dpos + ImVec2( px1-1, offset ), zoneColor.accentColor, zoneColor.thickness );
+ DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px1-1, offset + tsz.y ), dpos + ImVec2( px1-1, offset ), darkColor, zoneColor.thickness );
+ }
+ if( tsz.x < zsz )
+ {
+ const auto x = ( start - m_vd.zvStart ) * pxns + ( ( end - start ) * pxns - tsz.x ) / 2;
+ if( x < 0 || x > w - tsz.x )
+ {
+ ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
+ DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset ), 0xFFFFFFFF, zoneName );
+ ImGui::PopClipRect();
+ }
+ else if( ev.GpuStart() == ev.GpuEnd() )
+ {
+ DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset ), 0xFFFFFFFF, zoneName );
+ }
+ else
+ {
+ DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFFFFFFFF, zoneName );
+ }
+ }
+ else
+ {
+ ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
+ DrawTextContrast( draw, wpos + ImVec2( ( start - m_vd.zvStart ) * pxns, offset ), 0xFFFFFFFF, zoneName );
+ ImGui::PopClipRect();
+ }
+
+ if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y + 1 ) ) )
+ {
+ const auto zoneThread = thread != 0 ? thread : m_worker.DecompressThread( ev.Thread() );
+ ZoneTooltip( ev );
+
+ if( !m_zoomAnim.active && IsMouseClicked( 2 ) )
+ {
+ ZoomToZone( ev );
+ }
+ if( IsMouseClicked( 0 ) )
+ {
+ ShowZoneInfo( ev, zoneThread );
+ }
+
+ m_gpuThread = zoneThread;
+ m_gpuStart = ev.CpuStart();
+ m_gpuEnd = ev.CpuEnd();
+ }
+
+ ++it;
+ }
+ }
+ return maxdepth;
+}
+
+template
+int View::SkipGpuZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift )
+{
+ const auto delay = m_worker.GetDelay();
+ const auto resolution = m_worker.GetResolution();
+ // cast to uint64_t, so that unended zones (end = -1) are still drawn
+ auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - delay ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
+ if( it == vec.end() ) return depth;
+
+ const auto zitend = std::lower_bound( it, vec.end(), std::max( 0, m_vd.zvEnd + resolution ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuStart(), begin, drift ) < (uint64_t)r; } );
+ if( it == zitend ) return depth;
+
+ depth++;
+ int maxdepth = depth;
+
+ Adapter a;
+ while( it < zitend )
+ {
+ auto& ev = a(*it);
+ auto end = m_worker.GetZoneEnd( ev );
+ if( end == std::numeric_limits::max() ) break;
+ const auto start = AdjustGpuTime( ev.GpuStart(), begin, drift );
+ end = AdjustGpuTime( end, begin, drift );
+ const auto zsz = std::max( ( end - start ) * pxns, pxns * 0.5 );
+ if( zsz < MinVisSize )
+ {
+ const auto MinVisNs = MinVisSize * nspx;
+ auto px1ns = end - m_vd.zvStart;
+ auto nextTime = end + MinVisNs;
+ for(;;)
+ {
+ const auto prevIt = it;
+ it = std::lower_bound( it, zitend, nextTime, [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
+ if( it == prevIt ) ++it;
+ if( it == zitend ) break;
+ const auto nend = AdjustGpuTime( m_worker.GetZoneEnd( a(*it) ), begin, drift );
+ const auto nsnext = nend - m_vd.zvStart;
+ if( nsnext - px1ns >= MinVisNs * 2 ) break;
+ px1ns = nsnext;
+ nextTime = nend + nspx;
+ }
+ }
+ else
+ {
+ if( ev.Child() >= 0 )
+ {
+ const auto d = DispatchGpuZoneLevel( m_worker.GetGpuChildren( ev.Child() ), hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
+ if( d > maxdepth ) maxdepth = d;
+ }
+ ++it;
+ }
+ }
+ return maxdepth;
+}
+
+}
diff --git a/server/TracyView_Timeline.cpp b/server/TracyView_Timeline.cpp
index ca8f6079..58678e2c 100644
--- a/server/TracyView_Timeline.cpp
+++ b/server/TracyView_Timeline.cpp
@@ -4,6 +4,7 @@
#include "TracyMouse.hpp"
#include "TracyPrint.hpp"
#include "TracySourceView.hpp"
+#include "TracyTimelineItemGpu.hpp"
#include "TracyTimelineItemPlot.hpp"
#include "TracyTimelineItemThread.hpp"
#include "TracyView.hpp"
@@ -339,294 +340,13 @@ void View::DrawTimeline()
const auto to = 9.f;
const auto th = ( ty - to ) * sqrt( 3 ) * 0.5;
- // gpu zones
if( m_vd.drawGpuZones )
{
- for( size_t i=0; ithreadData.size() == 1;
- int depth = 0;
- offset += ostep;
- if( showFull && !v->threadData.empty() )
- {
- for( auto& td : v->threadData )
- {
- auto& tl = td.second.timeline;
- assert( !tl.empty() );
- if( tl.is_magic() )
- {
- auto& tlm = *(Vector*)&tl;
- if( tlm.front().GpuStart() >= 0 )
- {
- const auto begin = tlm.front().GpuStart();
- const auto drift = GpuDrift( v );
- if( !singleThread ) offset += sstep;
- const auto partDepth = DispatchGpuZoneLevel( tl, hover, pxns, int64_t( nspx ), wpos, offset, 0, v->thread, yMin, yMax, begin, drift );
- if( partDepth != 0 )
- {
- if( !singleThread )
- {
- ImGui::PushFont( m_smallFont );
- DrawTextContrast( draw, wpos + ImVec2( ty, offset-1-sstep ), 0xFFFFAAAA, m_worker.GetThreadName( td.first ) );
- DrawLine( draw, dpos + ImVec2( 0, offset+sty-sstep ), dpos + ImVec2( w, offset+sty-sstep ), 0x22FFAAAA );
- ImGui::PopFont();
- }
-
- offset += ostep * partDepth;
- depth += partDepth;
- }
- else if( !singleThread )
- {
- offset -= sstep;
- }
- }
- }
- else
- {
- if( tl.front()->GpuStart() >= 0 )
- {
- const auto begin = tl.front()->GpuStart();
- const auto drift = GpuDrift( v );
- if( !singleThread ) offset += sstep;
- const auto partDepth = DispatchGpuZoneLevel( tl, hover, pxns, int64_t( nspx ), wpos, offset, 0, v->thread, yMin, yMax, begin, drift );
- if( partDepth != 0 )
- {
- if( !singleThread )
- {
- ImGui::PushFont( m_smallFont );
- DrawTextContrast( draw, wpos + ImVec2( ty, offset-1-sstep ), 0xFFFFAAAA, m_worker.GetThreadName( td.first ) );
- DrawLine( draw, dpos + ImVec2( 0, offset+sty-sstep ), dpos + ImVec2( w, offset+sty-sstep ), 0x22FFAAAA );
- ImGui::PopFont();
- }
-
- offset += ostep * partDepth;
- depth += partDepth;
- }
- else if( !singleThread )
- {
- offset -= sstep;
- }
- }
- }
- }
- }
- offset += ostep * 0.2f;
-
- if( !m_vd.drawEmptyLabels && showFull && depth == 0 )
- {
- vis.height = 0;
- vis.offset = 0;
- offset = oldOffset;
- }
- else if( yPos + ostep >= yMin && yPos <= yMax )
- {
- DrawLine( draw, dpos + ImVec2( 0, oldOffset + ostep - 1 ), dpos + ImVec2( w, oldOffset + ostep - 1 ), 0x33FFFFFF );
-
- if( showFull )
- {
- draw->AddTriangleFilled( wpos + ImVec2( to/2, oldOffset + to/2 ), wpos + ImVec2( ty - to/2, oldOffset + to/2 ), wpos + ImVec2( ty * 0.5, oldOffset + to/2 + th ), 0xFFFFAAAA );
- }
- else
- {
- draw->AddTriangle( wpos + ImVec2( to/2, oldOffset + to/2 ), wpos + ImVec2( to/2, oldOffset + ty - to/2 ), wpos + ImVec2( to/2 + th, oldOffset + ty * 0.5 ), 0xFF886666, 2.0f );
- }
-
- const bool isMultithreaded = (v->type == GpuContextType::Vulkan) || (v->type == GpuContextType::OpenCL) || (v->type == GpuContextType::Direct3D12);
-
- float boxwidth;
- char buf[64];
- sprintf( buf, "%s context %zu", GpuContextNames[(int)v->type], i );
- if( v->name.Active() )
- {
- char tmp[4096];
- sprintf( tmp, "%s: %s", buf, m_worker.GetString( v->name ) );
- DrawTextContrast( draw, wpos + ImVec2( ty, oldOffset ), showFull ? 0xFFFFAAAA : 0xFF886666, tmp );
- boxwidth = ImGui::CalcTextSize( tmp ).x;
- }
- else
- {
- DrawTextContrast( draw, wpos + ImVec2( ty, oldOffset ), showFull ? 0xFFFFAAAA : 0xFF886666, buf );
- boxwidth = ImGui::CalcTextSize( buf ).x;
- }
-
- if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( ty + boxwidth, oldOffset + ty ) ) )
- {
- if( IsMouseClicked( 0 ) )
- {
- showFull = !showFull;
- }
- if( IsMouseClicked( 2 ) )
- {
- int64_t t0 = std::numeric_limits::max();
- int64_t t1 = std::numeric_limits::min();
- for( auto& td : v->threadData )
- {
- int64_t _t0;
- if( td.second.timeline.is_magic() )
- {
- _t0 = ((Vector*)&td.second.timeline)->front().GpuStart();
- }
- else
- {
- _t0 = td.second.timeline.front()->GpuStart();
- }
- if( _t0 >= 0 )
- {
- // FIXME
- t0 = std::min( t0, _t0 );
- if( td.second.timeline.is_magic() )
- {
- t1 = std::max( t1, std::min( m_worker.GetLastTime(), m_worker.GetZoneEnd( ((Vector*)&td.second.timeline)->back() ) ) );
- }
- else
- {
- t1 = std::max( t1, std::min( m_worker.GetLastTime(), m_worker.GetZoneEnd( *td.second.timeline.back() ) ) );
- }
- }
- }
- if( t0 < t1 )
- {
- ZoomToRange( t0, t1 );
- }
- }
- if( IsMouseClicked( 1 ) )
- {
- ImGui::OpenPopup( "menuPopup" );
- }
-
- ImGui::BeginTooltip();
- ImGui::TextUnformatted( buf );
- if( v->name.Active() ) TextFocused( "Name:", m_worker.GetString( v->name ) );
- ImGui::Separator();
- if( !isMultithreaded )
- {
- SmallColorBox( GetThreadColor( v->thread, 0 ) );
- ImGui::SameLine();
- TextFocused( "Thread:", m_worker.GetThreadName( v->thread ) );
- }
- else
- {
- if( !v->threadData.empty() )
- {
- if( v->threadData.size() == 1 )
- {
- auto it = v->threadData.begin();
- auto tid = it->first;
- if( tid == 0 )
- {
- if( !it->second.timeline.empty() )
- {
- if( it->second.timeline.is_magic() )
- {
- auto& tl = *(Vector*)&it->second.timeline;
- tid = m_worker.DecompressThread( tl.begin()->Thread() );
- }
- else
- {
- tid = m_worker.DecompressThread( (*it->second.timeline.begin())->Thread() );
- }
- }
- }
- SmallColorBox( GetThreadColor( tid, 0 ) );
- ImGui::SameLine();
- TextFocused( "Thread:", m_worker.GetThreadName( tid ) );
- ImGui::SameLine();
- ImGui::TextDisabled( "(%s)", RealToString( tid ) );
- if( m_worker.IsThreadFiber( tid ) )
- {
- ImGui::SameLine();
- TextColoredUnformatted( ImVec4( 0.2f, 0.6f, 0.2f, 1.f ), "Fiber" );
- }
- }
- else
- {
- ImGui::TextDisabled( "Threads:" );
- ImGui::Indent();
- for( auto& td : v->threadData )
- {
- SmallColorBox( GetThreadColor( td.first, 0 ) );
- ImGui::SameLine();
- ImGui::TextUnformatted( m_worker.GetThreadName( td.first ) );
- ImGui::SameLine();
- ImGui::TextDisabled( "(%s)", RealToString( td.first ) );
- }
- ImGui::Unindent();
- }
- }
- }
- if( !v->threadData.empty() )
- {
- int64_t t0 = std::numeric_limits::max();
- for( auto& td : v->threadData )
- {
- int64_t _t0;
- if( td.second.timeline.is_magic() )
- {
- _t0 = ((Vector*)&td.second.timeline)->front().GpuStart();
- }
- else
- {
- _t0 = td.second.timeline.front()->GpuStart();
- }
- if( _t0 >= 0 )
- {
- t0 = std::min( t0, _t0 );
- }
- }
- if( t0 != std::numeric_limits::max() )
- {
- TextFocused( "Appeared at", TimeToString( t0 ) );
- }
- }
- TextFocused( "Zone count:", RealToString( v->count ) );
- if( v->period != 1.f )
- {
- TextFocused( "Timestamp accuracy:", TimeToString( v->period ) );
- }
- if( v->overflow != 0 )
- {
- ImGui::Separator();
- ImGui::TextUnformatted( "GPU timer overflow has been detected." );
- TextFocused( "Timer resolution:", RealToString( 63 - TracyLzcnt( v->overflow ) ) );
- ImGui::SameLine();
- TextDisabledUnformatted( "bits" );
- }
- ImGui::EndTooltip();
- }
- }
-
- if( ImGui::BeginPopup( "menuPopup" ) )
- {
- if( ImGui::MenuItem( ICON_FA_EYE_SLASH " Hide" ) )
- {
- vis.visible = false;
- ImGui::CloseCurrentPopup();
- }
- ImGui::EndPopup();
- }
-
- m_tc.AdjustThreadHeight( vis, oldOffset, offset );
- ImGui::PopClipRect();
- ImGui::PopID();
+ m_tc.AddItem( v );
}
}
-
- // zones
if( m_vd.drawCpuData && m_worker.HasContextSwitches() )
{
offset = DrawCpuData( offset, pxns, wpos, hover, yMin, yMax );
diff --git a/server/TracyView_ZoneTimeline.cpp b/server/TracyView_ZoneTimeline.cpp
index 70ed998e..ec08fe99 100644
--- a/server/TracyView_ZoneTimeline.cpp
+++ b/server/TracyView_ZoneTimeline.cpp
@@ -888,266 +888,4 @@ int View::SkipZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, co
return maxdepth;
}
-int View::DispatchGpuZoneLevel( const Vector>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift )
-{
- const auto ty = ImGui::GetTextLineHeight();
- const auto ostep = ty + 1;
- const auto offset = _offset + ostep * depth;
-
- const auto yPos = wpos.y + offset;
- if( yPos + ostep >= yMin && yPos <= yMax )
- {
- if( vec.is_magic() )
- {
- return DrawGpuZoneLevel>( *(Vector*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
- }
- else
- {
- return DrawGpuZoneLevel>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
- }
- }
- else
- {
- if( vec.is_magic() )
- {
- return SkipGpuZoneLevel>( *(Vector*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
- }
- else
- {
- return SkipGpuZoneLevel>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
- }
- }
-}
-
-template
-int View::DrawGpuZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift )
-{
- const auto delay = m_worker.GetDelay();
- const auto resolution = m_worker.GetResolution();
- // cast to uint64_t, so that unended zones (end = -1) are still drawn
- auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - delay ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
- if( it == vec.end() ) return depth;
-
- const auto zitend = std::lower_bound( it, vec.end(), std::max( 0, m_vd.zvEnd + resolution ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuStart(), begin, drift ) < (uint64_t)r; } );
- if( it == zitend ) return depth;
-
- const auto w = ImGui::GetContentRegionAvail().x - 1;
- const auto ty = ImGui::GetTextLineHeight();
- const auto ostep = ty + 1;
- const auto offset = _offset + ostep * depth;
- auto draw = ImGui::GetWindowDrawList();
- const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
-
- depth++;
- int maxdepth = depth;
-
- Adapter a;
- while( it < zitend )
- {
- auto& ev = a(*it);
- auto end = m_worker.GetZoneEnd( ev );
- if( end == std::numeric_limits::max() ) break;
- const auto start = AdjustGpuTime( ev.GpuStart(), begin, drift );
- end = AdjustGpuTime( end, begin, drift );
- const auto zsz = std::max( ( end - start ) * pxns, pxns * 0.5 );
- if( zsz < MinVisSize )
- {
- const auto color = GetZoneColor( ev );
- const auto MinVisNs = MinVisSize * nspx;
- int num = 0;
- const auto px0 = ( start - m_vd.zvStart ) * pxns;
- auto px1ns = end - m_vd.zvStart;
- auto rend = end;
- auto nextTime = end + MinVisNs;
- for(;;)
- {
- const auto prevIt = it;
- it = std::lower_bound( it, zitend, std::max( 0, nextTime ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
- if( it == prevIt ) ++it;
- num += std::distance( prevIt, it );
- if( it == zitend ) break;
- const auto nend = AdjustGpuTime( m_worker.GetZoneEnd( a(*it) ), begin, drift );
- const auto nsnext = nend - m_vd.zvStart;
- if( nsnext < 0 || nsnext - px1ns >= MinVisNs * 2 ) break;
- px1ns = nsnext;
- rend = nend;
- nextTime = nend + nspx;
- }
- const auto px1 = px1ns * pxns;
- draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ), color );
- DrawZigZag( draw, wpos + ImVec2( 0, offset + ty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), ty/4, DarkenColor( color ) );
- if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty + 1 ) ) )
- {
- if( num > 1 )
- {
- ImGui::BeginTooltip();
- TextFocused( "Zones too small to display:", RealToString( num ) );
- ImGui::Separator();
- TextFocused( "Execution time:", TimeToString( rend - start ) );
- ImGui::EndTooltip();
-
- if( IsMouseClicked( 2 ) && rend - start > 0 )
- {
- ZoomToRange( start, rend );
- }
- }
- else
- {
- const auto zoneThread = thread != 0 ? thread : m_worker.DecompressThread( ev.Thread() );
- ZoneTooltip( ev );
-
- if( IsMouseClicked( 2 ) && rend - start > 0 )
- {
- ZoomToZone( ev );
- }
- if( IsMouseClicked( 0 ) )
- {
- ShowZoneInfo( ev, zoneThread );
- }
-
- m_gpuThread = zoneThread;
- m_gpuStart = ev.CpuStart();
- m_gpuEnd = ev.CpuEnd();
- }
- }
- const auto tmp = RealToString( num );
- const auto tsz = ImGui::CalcTextSize( tmp );
- if( tsz.x < px1 - px0 )
- {
- const auto x = px0 + ( px1 - px0 - tsz.x ) / 2;
- DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFF4488DD, tmp );
- }
- }
- else
- {
- if( ev.Child() >= 0 )
- {
- const auto d = DispatchGpuZoneLevel( m_worker.GetGpuChildren( ev.Child() ), hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
- if( d > maxdepth ) maxdepth = d;
- }
-
- const char* zoneName = m_worker.GetZoneName( ev );
- auto tsz = ImGui::CalcTextSize( zoneName );
-
- const auto pr0 = ( start - m_vd.zvStart ) * pxns;
- const auto pr1 = ( end - m_vd.zvStart ) * pxns;
- const auto px0 = std::max( pr0, -10.0 );
- const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } );
- const auto zoneColor = GetZoneColorData( ev );
- draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.color );
- if( zoneColor.highlight )
- {
- draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.accentColor, 0.f, -1, zoneColor.thickness );
- }
- else
- {
- const auto darkColor = DarkenColor( zoneColor.color );
- DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px0, offset ), dpos + ImVec2( px1-1, offset ), zoneColor.accentColor, zoneColor.thickness );
- DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px1-1, offset + tsz.y ), dpos + ImVec2( px1-1, offset ), darkColor, zoneColor.thickness );
- }
- if( tsz.x < zsz )
- {
- const auto x = ( start - m_vd.zvStart ) * pxns + ( ( end - start ) * pxns - tsz.x ) / 2;
- if( x < 0 || x > w - tsz.x )
- {
- ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
- DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset ), 0xFFFFFFFF, zoneName );
- ImGui::PopClipRect();
- }
- else if( ev.GpuStart() == ev.GpuEnd() )
- {
- DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset ), 0xFFFFFFFF, zoneName );
- }
- else
- {
- DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFFFFFFFF, zoneName );
- }
- }
- else
- {
- ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
- DrawTextContrast( draw, wpos + ImVec2( ( start - m_vd.zvStart ) * pxns, offset ), 0xFFFFFFFF, zoneName );
- ImGui::PopClipRect();
- }
-
- if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y + 1 ) ) )
- {
- const auto zoneThread = thread != 0 ? thread : m_worker.DecompressThread( ev.Thread() );
- ZoneTooltip( ev );
-
- if( !m_zoomAnim.active && IsMouseClicked( 2 ) )
- {
- ZoomToZone( ev );
- }
- if( IsMouseClicked( 0 ) )
- {
- ShowZoneInfo( ev, zoneThread );
- }
-
- m_gpuThread = zoneThread;
- m_gpuStart = ev.CpuStart();
- m_gpuEnd = ev.CpuEnd();
- }
-
- ++it;
- }
- }
- return maxdepth;
-}
-
-template
-int View::SkipGpuZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift )
-{
- const auto delay = m_worker.GetDelay();
- const auto resolution = m_worker.GetResolution();
- // cast to uint64_t, so that unended zones (end = -1) are still drawn
- auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - delay ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
- if( it == vec.end() ) return depth;
-
- const auto zitend = std::lower_bound( it, vec.end(), std::max( 0, m_vd.zvEnd + resolution ), [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuStart(), begin, drift ) < (uint64_t)r; } );
- if( it == zitend ) return depth;
-
- depth++;
- int maxdepth = depth;
-
- Adapter a;
- while( it < zitend )
- {
- auto& ev = a(*it);
- auto end = m_worker.GetZoneEnd( ev );
- if( end == std::numeric_limits::max() ) break;
- const auto start = AdjustGpuTime( ev.GpuStart(), begin, drift );
- end = AdjustGpuTime( end, begin, drift );
- const auto zsz = std::max( ( end - start ) * pxns, pxns * 0.5 );
- if( zsz < MinVisSize )
- {
- const auto MinVisNs = MinVisSize * nspx;
- auto px1ns = end - m_vd.zvStart;
- auto nextTime = end + MinVisNs;
- for(;;)
- {
- const auto prevIt = it;
- it = std::lower_bound( it, zitend, nextTime, [begin, drift] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)AdjustGpuTime( a(l).GpuEnd(), begin, drift ) < (uint64_t)r; } );
- if( it == prevIt ) ++it;
- if( it == zitend ) break;
- const auto nend = AdjustGpuTime( m_worker.GetZoneEnd( a(*it) ), begin, drift );
- const auto nsnext = nend - m_vd.zvStart;
- if( nsnext - px1ns >= MinVisNs * 2 ) break;
- px1ns = nsnext;
- nextTime = nend + nspx;
- }
- }
- else
- {
- if( ev.Child() >= 0 )
- {
- const auto d = DispatchGpuZoneLevel( m_worker.GetGpuChildren( ev.Child() ), hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
- if( d > maxdepth ) maxdepth = d;
- }
- ++it;
- }
- }
- return maxdepth;
-}
-
}