mirror of
https://github.com/wolfpld/tracy
synced 2025-04-29 04:23:51 +00:00
Migrate drawing GPU data to the new timeline item system.
This commit is contained in:
parent
ec3e88ce53
commit
60579d6334
@ -138,6 +138,7 @@
|
||||
<ClCompile Include="..\..\..\server\TracyThreadCompress.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineController.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineItem.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineItemGpu.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineItemPlot.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineItemThread.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyUserData.cpp" />
|
||||
@ -153,6 +154,7 @@
|
||||
<ClCompile Include="..\..\..\server\TracyView_FrameOverview.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyView_FrameTimeline.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyView_FrameTree.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyView_GpuTimeline.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyView_Locks.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyView_Memory.cpp" />
|
||||
<ClCompile Include="..\..\..\server\TracyView_Messages.cpp" />
|
||||
@ -277,6 +279,7 @@
|
||||
<ClInclude Include="..\..\..\server\TracyThreadCompress.hpp" />
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineController.hpp" />
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineItem.hpp" />
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineItemGpu.hpp" />
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineItemPlot.hpp" />
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineItemThread.hpp" />
|
||||
<ClInclude Include="..\..\..\server\TracyUserData.hpp" />
|
||||
|
@ -366,6 +366,12 @@
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineItemThread.cpp">
|
||||
<Filter>server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\server\TracyTimelineItemGpu.cpp">
|
||||
<Filter>server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\server\TracyView_GpuTimeline.cpp">
|
||||
<Filter>server</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\server\TracyEvent.hpp">
|
||||
@ -743,6 +749,9 @@
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineItemThread.hpp">
|
||||
<Filter>server</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\server\TracyTimelineItemGpu.hpp">
|
||||
<Filter>server</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="DebugVis.natvis" />
|
||||
|
195
server/TracyTimelineItemGpu.cpp
Normal file
195
server/TracyTimelineItemGpu.cpp
Normal file
@ -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<GpuEvent>*)&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<int64_t>::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<int64_t>::max();
|
||||
for( auto& td : m_gpu->threadData )
|
||||
{
|
||||
int64_t t0;
|
||||
if( td.second.timeline.is_magic() )
|
||||
{
|
||||
t0 = ((Vector<GpuEvent>*)&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<int64_t>::min();
|
||||
for( auto& td : m_gpu->threadData )
|
||||
{
|
||||
int64_t t0;
|
||||
if( td.second.timeline.is_magic() )
|
||||
{
|
||||
t0 = ((Vector<GpuEvent>*)&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<GpuEvent>*)&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 );
|
||||
}
|
||||
|
||||
}
|
38
server/TracyTimelineItemGpu.hpp
Normal file
38
server/TracyTimelineItemGpu.hpp
Normal file
@ -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
|
@ -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;
|
||||
|
354
server/TracyView_GpuTimeline.cpp
Normal file
354
server/TracyView_GpuTimeline.cpp
Normal file
@ -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<GpuEvent>*)&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<short_ptr<GpuEvent>>& 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<VectorAdapterDirect<GpuEvent>>( *(Vector<GpuEvent>*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
else
|
||||
{
|
||||
return DrawGpuZoneLevel<VectorAdapterPointer<GpuEvent>>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( vec.is_magic() )
|
||||
{
|
||||
return SkipGpuZoneLevel<VectorAdapterDirect<GpuEvent>>( *(Vector<GpuEvent>*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
else
|
||||
{
|
||||
return SkipGpuZoneLevel<VectorAdapterPointer<GpuEvent>>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Adapter, typename V>
|
||||
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<int64_t>( 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<int64_t>( 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<int64_t>::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<int64_t>( 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<typename Adapter, typename V>
|
||||
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<int64_t>( 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<int64_t>( 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<int64_t>::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;
|
||||
}
|
||||
|
||||
}
|
@ -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; i<m_worker.GetGpuData().size(); i++ )
|
||||
for( auto& v : m_worker.GetGpuData() )
|
||||
{
|
||||
const auto& v = m_worker.GetGpuData()[i];
|
||||
auto& vis = m_tc.Vis( v );
|
||||
if( !vis.visible )
|
||||
{
|
||||
vis.height = 0;
|
||||
vis.offset = 0;
|
||||
continue;
|
||||
}
|
||||
bool& showFull = vis.showFull;
|
||||
ImGui::PushID( &vis );
|
||||
|
||||
const auto yPos = m_tc.AdjustThreadPosition( vis, wpos.y, offset );
|
||||
const auto oldOffset = offset;
|
||||
ImGui::PushClipRect( wpos, wpos + ImVec2( w, oldOffset + vis.height ), true );
|
||||
|
||||
const auto singleThread = v->threadData.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<GpuEvent>*)&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<int64_t>::max();
|
||||
int64_t t1 = std::numeric_limits<int64_t>::min();
|
||||
for( auto& td : v->threadData )
|
||||
{
|
||||
int64_t _t0;
|
||||
if( td.second.timeline.is_magic() )
|
||||
{
|
||||
_t0 = ((Vector<GpuEvent>*)&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<GpuEvent>*)&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<GpuEvent>*)&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<int64_t>::max();
|
||||
for( auto& td : v->threadData )
|
||||
{
|
||||
int64_t _t0;
|
||||
if( td.second.timeline.is_magic() )
|
||||
{
|
||||
_t0 = ((Vector<GpuEvent>*)&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<int64_t>::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<TimelineItemGpu>( v );
|
||||
}
|
||||
}
|
||||
|
||||
// zones
|
||||
if( m_vd.drawCpuData && m_worker.HasContextSwitches() )
|
||||
{
|
||||
offset = DrawCpuData( offset, pxns, wpos, hover, yMin, yMax );
|
||||
|
@ -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<short_ptr<GpuEvent>>& 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<VectorAdapterDirect<GpuEvent>>( *(Vector<GpuEvent>*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
else
|
||||
{
|
||||
return DrawGpuZoneLevel<VectorAdapterPointer<GpuEvent>>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( vec.is_magic() )
|
||||
{
|
||||
return SkipGpuZoneLevel<VectorAdapterDirect<GpuEvent>>( *(Vector<GpuEvent>*)&vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
else
|
||||
{
|
||||
return SkipGpuZoneLevel<VectorAdapterPointer<GpuEvent>>( vec, hover, pxns, nspx, wpos, _offset, depth, thread, yMin, yMax, begin, drift );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Adapter, typename V>
|
||||
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<int64_t>( 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<int64_t>( 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<int64_t>::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<int64_t>( 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<typename Adapter, typename V>
|
||||
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<int64_t>( 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<int64_t>( 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<int64_t>::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;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user