mirror of
https://github.com/wolfpld/tracy.git
synced 2026-10-23 01:00:54 +00:00
Add filtering and hierarchical view to plots selection
- Filter text allows restricting plots to ones matching the name - Hierarchical view displays plots as a tree, separating levels based on slash-separated names, i.e.: "GPU/Counters/Draws" and "GPU/Counters/Primitives" will be leaf nodes under GPU > Counters
This commit is contained in:
@@ -177,6 +177,7 @@ bool UserData::Save()
|
||||
{ "frameTarget", m_viewData.frameTarget },
|
||||
{ "shortenName", (int)m_viewData.shortenName },
|
||||
{ "plotHeight", m_viewData.plotHeight },
|
||||
{ "plotsHierarchy", m_viewData.plotsHierarchy },
|
||||
} },
|
||||
};
|
||||
|
||||
@@ -278,6 +279,7 @@ bool UserData::Load()
|
||||
LoadValue( options, "frameTarget", m_viewData.frameTarget );
|
||||
LoadValueCast( options, "shortenName", m_viewData.shortenName );
|
||||
LoadValue( options, "plotHeight", m_viewData.plotHeight );
|
||||
LoadValue( options, "plotsHierarchy", m_viewData.plotsHierarchy );
|
||||
}
|
||||
|
||||
if( json.contains( "sourceSubstitutions" ) )
|
||||
|
||||
@@ -637,6 +637,7 @@ private:
|
||||
ImGuiTextFilter m_statisticsFilter;
|
||||
ImGuiTextFilter m_statisticsImageFilter;
|
||||
ImGuiTextFilter m_userTextFilter;
|
||||
ImGuiTextFilter m_plotFilter;
|
||||
unordered_flat_set<Worker::ZoneThreadData*> m_filteredZones;
|
||||
|
||||
Region m_highlight;
|
||||
|
||||
@@ -54,6 +54,7 @@ struct ViewData
|
||||
uint8_t inheritParentColors = true;
|
||||
uint8_t forceColors = false;
|
||||
uint8_t ghostZones = true;
|
||||
uint8_t plotsHierarchy = false;
|
||||
ShortenName shortenName = ShortenName::NoSpaceAndNormalize;
|
||||
|
||||
uint32_t frameTarget = 60;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <inttypes.h>
|
||||
#include <random>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include "TracyFilesystem.hpp"
|
||||
#include "TracyImGui.hpp"
|
||||
@@ -28,6 +31,102 @@ static void DefaultMarker( bool active, bool tooltip = true )
|
||||
}
|
||||
}
|
||||
|
||||
struct PlotTreeNode
|
||||
{
|
||||
std::map<std::string, PlotTreeNode> children;
|
||||
std::vector<const PlotData*> plots;
|
||||
};
|
||||
|
||||
static void BuildPlotTree( PlotTreeNode& root, const std::vector<const PlotData*>& plots, const Worker& worker )
|
||||
{
|
||||
for( const auto* p : plots )
|
||||
{
|
||||
const char* name = worker.GetString( p->name );
|
||||
PlotTreeNode* node = &root;
|
||||
const char* segStart = name;
|
||||
for(;;)
|
||||
{
|
||||
const char* slash = strchr( segStart, '/' );
|
||||
if( !slash )
|
||||
{
|
||||
node->plots.emplace_back( p );
|
||||
break;
|
||||
}
|
||||
node = &node->children[std::string( segStart, slash - segStart )];
|
||||
segStart = slash + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CountPlotTreeVisibility( const PlotTreeNode& node, TimelineController& tc, size_t& total, size_t& visible )
|
||||
{
|
||||
for( const auto& child : node.children ) CountPlotTreeVisibility( child.second, tc, total, visible );
|
||||
for( const auto* p : node.plots )
|
||||
{
|
||||
total++;
|
||||
if( tc.GetItem( p ).IsVisible() ) visible++;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlotTreeVisibility( PlotTreeNode& node, TimelineController& tc, bool visible )
|
||||
{
|
||||
for( auto& child : node.children ) SetPlotTreeVisibility( child.second, tc, visible );
|
||||
for( const auto* p : node.plots )
|
||||
{
|
||||
tc.GetItem( p ).SetVisible( visible );
|
||||
}
|
||||
}
|
||||
|
||||
// fullPath is the '/'-joined path to this node, used as a stable ImGui ID (the tree is rebuilt every frame).
|
||||
static void DrawPlotTreeNode( const std::string& label, const std::string& fullPath, PlotTreeNode& node, TimelineController& tc, const Worker& worker )
|
||||
{
|
||||
size_t total = 0, visibleCount = 0;
|
||||
CountPlotTreeVisibility( node, tc, total, visibleCount );
|
||||
bool allVisible = total > 0 && visibleCount == total;
|
||||
const bool mixed = visibleCount > 0 && visibleCount < total;
|
||||
|
||||
const bool nodeExpand = ImGui::TreeNodeEx( fullPath.c_str(), ImGuiTreeNodeFlags_None, "" );
|
||||
ImGui::SameLine();
|
||||
const std::string checkboxId = "##hdr_" + fullPath;
|
||||
ImGui::PushItemFlag( ImGuiItemFlags_MixedValue, mixed );
|
||||
const bool clicked = SmallCheckbox( checkboxId.c_str(), &allVisible );
|
||||
ImGui::PopItemFlag();
|
||||
if( clicked )
|
||||
{
|
||||
SetPlotTreeVisibility( node, tc, allVisible );
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted( label.c_str() );
|
||||
|
||||
if( nodeExpand )
|
||||
{
|
||||
for( auto& child : node.children )
|
||||
{
|
||||
DrawPlotTreeNode( child.first, fullPath + "/" + child.first, child.second, tc, worker );
|
||||
}
|
||||
for( const auto* p : node.plots )
|
||||
{
|
||||
const char* fullName = worker.GetString( p->name );
|
||||
const char* slash = strrchr( fullName, '/' );
|
||||
const char* leaf = slash ? slash + 1 : fullName;
|
||||
|
||||
SmallColorBox( GetPlotColor( *p, worker ) );
|
||||
ImGui::SameLine();
|
||||
bool visible = tc.GetItem( p ).IsVisible();
|
||||
char leafId[256];
|
||||
snprintf( leafId, sizeof( leafId ), "%s##%p", leaf, (const void*)p );
|
||||
if( SmallCheckbox( leafId, &visible ) )
|
||||
{
|
||||
tc.GetItem( p ).SetVisible( visible );
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "%s data points", RealToString( p->data.size() ) );
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void View::DrawOptions()
|
||||
{
|
||||
static bool default_markers_active = false;
|
||||
@@ -678,9 +777,25 @@ void View::DrawOptions()
|
||||
if( expand )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
bool hierarchy = m_vd.plotsHierarchy;
|
||||
if( ImGui::RadioButton( "Flat", !hierarchy ) ) m_vd.plotsHierarchy = false;
|
||||
ImGui::SameLine();
|
||||
if( ImGui::RadioButton( "Hierarchical", hierarchy ) ) m_vd.plotsHierarchy = true;
|
||||
hierarchy = m_vd.plotsHierarchy;
|
||||
|
||||
std::vector<const PlotData*> filteredPlots;
|
||||
filteredPlots.reserve( m_worker.GetPlots().size() );
|
||||
for( const auto& p : m_worker.GetPlots() )
|
||||
{
|
||||
if( m_plotFilter.PassFilter( m_worker.GetString( p->name ) ) )
|
||||
{
|
||||
filteredPlots.emplace_back( p );
|
||||
}
|
||||
}
|
||||
|
||||
if( ImGui::SmallButton( "Select all" ) )
|
||||
{
|
||||
for( const auto& p : m_worker.GetPlots() )
|
||||
for( const auto* p : filteredPlots )
|
||||
{
|
||||
m_tc.GetItem( p ).SetVisible( true );
|
||||
}
|
||||
@@ -688,19 +803,47 @@ void View::DrawOptions()
|
||||
ImGui::SameLine();
|
||||
if( ImGui::SmallButton( "Unselect all" ) )
|
||||
{
|
||||
for( const auto& p : m_worker.GetPlots() )
|
||||
for( const auto* p : filteredPlots )
|
||||
{
|
||||
m_tc.GetItem( p ).SetVisible( false );
|
||||
}
|
||||
}
|
||||
|
||||
for( const auto& p : m_worker.GetPlots() )
|
||||
ImGui::SameLine();
|
||||
m_plotFilter.Draw( ICON_FA_FILTER "###plotFilter", 200 );
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( ICON_FA_DELETE_LEFT " Clear###plotFilterClear" ) )
|
||||
{
|
||||
SmallColorBox( GetPlotColor( *p, m_worker ) );
|
||||
ImGui::SameLine();
|
||||
m_tc.GetItem( p ).VisibilityCheckbox();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "%s data points", RealToString( p->data.size() ) );
|
||||
m_plotFilter.Clear();
|
||||
}
|
||||
|
||||
if( hierarchy )
|
||||
{
|
||||
PlotTreeNode root;
|
||||
BuildPlotTree( root, filteredPlots, m_worker );
|
||||
|
||||
for( auto& child : root.children )
|
||||
{
|
||||
DrawPlotTreeNode( child.first, child.first, child.second, m_tc, m_worker );
|
||||
}
|
||||
for( const auto* p : root.plots )
|
||||
{
|
||||
SmallColorBox( GetPlotColor( *p, m_worker ) );
|
||||
ImGui::SameLine();
|
||||
m_tc.GetItem( p ).VisibilityCheckbox();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "%s data points", RealToString( p->data.size() ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const auto* p : filteredPlots )
|
||||
{
|
||||
SmallColorBox( GetPlotColor( *p, m_worker ) );
|
||||
ImGui::SameLine();
|
||||
m_tc.GetItem( p ).VisibilityCheckbox();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "%s data points", RealToString( p->data.size() ) );
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user