diff --git a/profiler/src/main.cpp b/profiler/src/main.cpp index 751780a9..6fcea999 100644 --- a/profiler/src/main.cpp +++ b/profiler/src/main.cpp @@ -76,6 +76,8 @@ static void SetWindowTitleCallback( const char* title ) s_customTitle = true; } +static void DrawContents(); + std::vector::const_iterator> RebuildConnectionHistory( const std::unordered_map& connHistMap ) { std::vector::const_iterator> ret; @@ -97,16 +99,31 @@ struct ClientData std::string address; }; +enum class ViewShutdown { False, True, Join }; + +static tracy::flat_hash_map clients; +static std::unique_ptr view; +static tracy::BadVersionState badVer; +static int port = 8086; +static const char* connectTo = nullptr; +static char title[128]; +static std::thread loadThread; +static std::unique_ptr broadcastListen; +static std::mutex resolvLock; +static tracy::flat_hash_map resolvMap; +static ResolvService resolv( port ); +static ImFont* bigFont; +static ImFont* smallFont; +static ImFont* fixedWidth; +static char addr[1024] = { "127.0.0.1" }; +static std::unordered_map connHistMap; +static std::vector::const_iterator> connHistVec; +static ViewShutdown viewShutdown = ViewShutdown::False; +static double animTime = 0; +static float dpiScale = 1.f; + int main( int argc, char** argv ) { - tracy::flat_hash_map clients; - - std::unique_ptr view; - tracy::BadVersionState badVer; - - int port = 8086; - const char* connectTo = nullptr; - if( argc == 2 ) { auto f = std::unique_ptr( tracy::FileRead::Open( argv[1] ) ); @@ -141,7 +158,6 @@ int main( int argc, char** argv ) view = std::make_unique( connectTo, port ); } - char title[128]; sprintf( title, "Tracy Profiler %i.%i.%i", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch ); std::string winPosFile = tracy::GetSavePath( "window.position" ); @@ -170,8 +186,6 @@ int main( int argc, char** argv ) } std::string connHistFile = tracy::GetSavePath( "connection.history" ); - std::unordered_map connHistMap; - std::vector::const_iterator> connHistVec; { FILE* f = fopen( connHistFile.c_str(), "rb" ); if( f ) @@ -222,7 +236,6 @@ int main( int argc, char** argv ) glfwSwapInterval(1); // Enable vsync gl3wInit(); - float dpiScale = 1.f; #ifdef _WIN32 typedef UINT(*GDFS)(void); GDFS getDpiForSystem = nullptr; @@ -259,9 +272,9 @@ int main( int argc, char** argv ) io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Arimo_compressed_data, tracy::Arimo_compressed_size, 15.0f * dpiScale, nullptr, rangesBasic ); io.Fonts->AddFontFromMemoryCompressedTTF( tracy::FontAwesomeSolid_compressed_data, tracy::FontAwesomeSolid_compressed_size, 14.0f * dpiScale, &configMerge, rangesIcons ); - auto fixedWidth = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Cousine_compressed_data, tracy::Cousine_compressed_size, 15.0f * dpiScale ); - auto bigFont = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Arimo_compressed_data, tracy::Cousine_compressed_size, 20.0f * dpiScale ); - auto smallFont = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Arimo_compressed_data, tracy::Cousine_compressed_size, 10.0f * dpiScale ); + fixedWidth = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Cousine_compressed_data, tracy::Cousine_compressed_size, 15.0f * dpiScale ); + bigFont = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Arimo_compressed_data, tracy::Cousine_compressed_size, 20.0f * dpiScale ); + smallFont = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::Arimo_compressed_data, tracy::Cousine_compressed_size, 10.0f * dpiScale ); ImGuiFreeType::BuildFontAtlas( io.Fonts, ImGuiFreeType::LightHinting ); @@ -273,440 +286,18 @@ int main( int argc, char** argv ) style.Colors[ImGuiCol_ScrollbarBg] = ImVec4( 1, 1, 1, 0.03f ); style.ScaleAllSizes( dpiScale ); - ImVec4 clear_color = ImColor(114, 144, 154); - - char addr[1024] = { "127.0.0.1" }; - - std::thread loadThread; - std::unique_ptr broadcastListen; - - enum class ViewShutdown { False, True, Join }; - ViewShutdown viewShutdown = ViewShutdown::False; - - std::mutex resolvLock; - tracy::flat_hash_map resolvMap; - ResolvService resolv( port ); - glfwShowWindow( window ); - double time = 0; // Main loop while (!glfwWindowShouldClose(window)) { glfwPollEvents(); - if( glfwGetWindowAttrib( window, GLFW_ICONIFIED ) ) { std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); continue; } - - int display_w, display_h; - glfwGetFramebufferSize(window, &display_w, &display_h); - - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - if( !view ) - { - if( s_customTitle ) - { - s_customTitle = false; - glfwSetWindowTitle( window, title ); - } - - const auto time = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count(); - if( !broadcastListen ) - { - broadcastListen = std::make_unique(); - if( !broadcastListen->Listen( port ) ) - { - broadcastListen.reset(); - } - } - else - { - tracy::IpAddress addr; - size_t len; - auto msg = broadcastListen->Read( len, addr ); - if( msg ) - { - assert( len <= sizeof( tracy::BroadcastMessage ) ); - tracy::BroadcastMessage bm; - memcpy( &bm, msg, len ); - - if( bm.broadcastVersion == tracy::BroadcastVersion ) - { - const uint32_t protoVer = bm.protocolVersion; - const auto procname = bm.programName; - const auto activeTime = bm.activeTime; - auto address = addr.GetText(); - - const auto ipNumerical = addr.GetNumber(); - auto it = clients.find( ipNumerical ); - if( it == clients.end() ) - { - std::string ip( address ); - resolvLock.lock(); - if( resolvMap.find( ip ) == resolvMap.end() ) - { - resolvMap.emplace( ip, ip ); - resolv.Query( ipNumerical, [&resolvMap, &resolvLock, ip] ( std::string&& name ) { - std::lock_guard lock( resolvLock ); - auto it = resolvMap.find( ip ); - assert( it != resolvMap.end() ); - std::swap( it->second, name ); - } ); - } - resolvLock.unlock(); - clients.emplace( addr.GetNumber(), ClientData { time, protoVer, activeTime, procname, std::move( ip ) } ); - } - else - { - it->second.time = time; - it->second.activeTime = activeTime; - if( it->second.protocolVersion != protoVer ) it->second.protocolVersion = protoVer; - if( strcmp( it->second.procName.c_str(), procname ) != 0 ) it->second.procName = procname; - } - } - } - auto it = clients.begin(); - while( it != clients.end() ) - { - const auto diff = time - it->second.time; - if( diff > 4000 ) // 4s - { - it = clients.erase( it ); - } - else - { - ++it; - } - } - } - - setlocale( LC_NUMERIC, "C" ); - style.Colors[ImGuiCol_WindowBg] = ImVec4( 0.129f, 0.137f, 0.11f, 1.f ); - ImGui::Begin( "Get started", nullptr, ImGuiWindowFlags_AlwaysAutoResize ); - char buf[128]; - sprintf( buf, "Tracy Profiler %i.%i.%i", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch ); - ImGui::PushFont( bigFont ); - tracy::TextCentered( buf ); - ImGui::PopFont(); - ImGui::Spacing(); - if( ImGui::Button( ICON_FA_BOOK " Manual" ) ) - { - OpenWebpage( "https://bitbucket.org/wolfpld/tracy/downloads/tracy.pdf" ); - } - ImGui::SameLine(); - if( ImGui::Button( ICON_FA_GLOBE_AMERICAS " Web" ) ) - { - OpenWebpage( "https://bitbucket.org/wolfpld/tracy" ); - } - ImGui::SameLine(); - if( ImGui::Button( ICON_FA_COMMENT " Chat" ) ) - { - OpenWebpage( "https://discord.gg/pk78auc" ); - } - ImGui::SameLine(); - if( ImGui::Button( ICON_FA_VIDEO " Tutorial" ) ) - { - ImGui::OpenPopup( "tutorial" ); - } - if( ImGui::BeginPopup( "tutorial" ) ) - { - if( ImGui::Selectable( ICON_FA_VIDEO " Introduction to the Tracy Profiler" ) ) - { - OpenWebpage( "https://www.youtube.com/watch?v=fB5B46lbapc" ); - } - if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.3" ) ) - { - OpenWebpage( "https://www.youtube.com/watch?v=3SXpDpDh2Uo" ); - } - if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.4" ) ) - { - OpenWebpage( "https://www.youtube.com/watch?v=eAkgkaO8B9o" ); - } - if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.5" ) ) - { - OpenWebpage( "https://www.youtube.com/watch?v=P6E7qLMmzTQ" ); - } - if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.6" ) ) - { - OpenWebpage( "https://www.youtube.com/watch?v=uJkrFgriuOo" ); - } - ImGui::EndPopup(); - } - ImGui::Separator(); - ImGui::TextUnformatted( "Client address" ); - bool connectClicked = false; - connectClicked |= ImGui::InputTextWithHint( "###connectaddress", "Enter address", addr, 1024, ImGuiInputTextFlags_EnterReturnsTrue ); - if( !connHistVec.empty() ) - { - ImGui::SameLine(); - if( ImGui::BeginCombo( "##frameCombo", nullptr, ImGuiComboFlags_NoPreview ) ) - { - int idxRemove = -1; - const auto sz = std::min( 5, connHistVec.size() ); - for( size_t i=0; ifirst; - if( ImGui::Selectable( str.c_str() ) ) - { - memcpy( addr, str.c_str(), str.size() + 1 ); - } - if( ImGui::IsItemHovered() && ImGui::IsKeyPressed( ImGui::GetKeyIndex( ImGuiKey_Delete ), false ) ) - { - idxRemove = (int)i; - } - } - if( idxRemove >= 0 ) - { - connHistMap.erase( connHistVec[idxRemove] ); - connHistVec = RebuildConnectionHistory( connHistMap ); - } - ImGui::EndCombo(); - } - } - connectClicked |= ImGui::Button( ICON_FA_WIFI " Connect" ); - if( connectClicked && *addr && !loadThread.joinable() ) - { - std::string addrStr( addr ); - auto it = connHistMap.find( addrStr ); - if( it != connHistMap.end() ) - { - it->second++; - } - else - { - connHistMap.emplace( std::move( addrStr ), 1 ); - } - connHistVec = RebuildConnectionHistory( connHistMap ); - - view = std::make_unique( addr, port, fixedWidth, smallFont, bigFont, SetWindowTitleCallback ); - } - ImGui::SameLine( 0, ImGui::GetFontSize() * 2 ); - if( ImGui::Button( ICON_FA_FOLDER_OPEN " Open saved trace" ) && !loadThread.joinable() ) - { - nfdchar_t* fn; - auto res = NFD_OpenDialog( "tracy", nullptr, &fn ); - if( res == NFD_OKAY ) - { - try - { - auto f = std::shared_ptr( tracy::FileRead::Open( fn ) ); - if( f ) - { - loadThread = std::thread( [&view, f, &badVer, fixedWidth, smallFont, bigFont] { - try - { - view = std::make_unique( *f, fixedWidth, smallFont, bigFont, SetWindowTitleCallback ); - } - catch( const tracy::UnsupportedVersion& e ) - { - badVer.state = tracy::BadVersionState::UnsupportedVersion; - badVer.version = e.version; - } - catch( const tracy::LegacyVersion& e ) - { - badVer.state = tracy::BadVersionState::LegacyVersion; - badVer.version = e.version; - } - } ); - } - } - catch( const tracy::NotTracyDump& ) - { - badVer.state = tracy::BadVersionState::BadFile; - } - } - } - - if( badVer.state != tracy::BadVersionState::Ok ) - { - if( loadThread.joinable() ) { loadThread.join(); } - tracy::BadVersion( badVer ); - } - - if( !clients.empty() ) - { - ImGui::Separator(); - ImGui::TextUnformatted( "Discovered clients:" ); - ImGui::Separator(); - static bool widthSet = false; - ImGui::Columns( 3 ); - if( !widthSet ) - { - widthSet = true; - const auto w = ImGui::GetWindowWidth(); - ImGui::SetColumnWidth( 0, w * 0.35f ); - ImGui::SetColumnWidth( 1, w * 0.175f ); - ImGui::SetColumnWidth( 2, w * 0.425f ); - } - std::lock_guard lock( resolvLock ); - for( auto& v : clients ) - { - const bool badProto = v.second.protocolVersion != tracy::ProtocolVersion; - bool sel = false; - const auto& name = resolvMap.find( v.second.address ); - assert( name != resolvMap.end() ); - ImGuiSelectableFlags flags = ImGuiSelectableFlags_SpanAllColumns; - if( badProto ) flags |= ImGuiSelectableFlags_Disabled; - if( ImGui::Selectable( name->second.c_str(), &sel, flags ) && !loadThread.joinable() ) - { - view = std::make_unique( v.second.address.c_str(), port, fixedWidth, smallFont, bigFont, SetWindowTitleCallback ); - } - ImGui::NextColumn(); - const auto acttime = ( v.second.activeTime + ( time - v.second.time ) / 1000 ) * 1000000000ll; - if( badProto ) - { - tracy::TextDisabledUnformatted( tracy::TimeToString( acttime ) ); - } - else - { - ImGui::TextUnformatted( tracy::TimeToString( acttime ) ); - } - ImGui::NextColumn(); - if( badProto ) - { - tracy::TextDisabledUnformatted( v.second.procName.c_str() ); - } - else - { - ImGui::TextUnformatted( v.second.procName.c_str() ); - } - ImGui::NextColumn(); - } - ImGui::EndColumns(); - } - - ImGui::End(); - } - else - { - if( broadcastListen ) - { - broadcastListen.reset(); - clients.clear(); - } - if( loadThread.joinable() ) loadThread.join(); - view->NotifyRootWindowSize( display_w, display_h ); - if( !view->Draw() ) - { - viewShutdown = ViewShutdown::True; - loadThread = std::thread( [&viewShutdown, view = std::move( view )] () mutable { - view.reset(); - viewShutdown = ViewShutdown::Join; - } ); - } - } - auto& progress = tracy::Worker::GetLoadProgress(); - auto totalProgress = progress.total.load( std::memory_order_relaxed ); - if( totalProgress != 0 ) - { - ImGui::OpenPopup( "Loading trace..." ); - } - if( ImGui::BeginPopupModal( "Loading trace...", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) - { - tracy::TextCentered( ICON_FA_HOURGLASS_HALF ); - - time += io.DeltaTime; - tracy::DrawWaitingDots( time ); - - auto currProgress = progress.progress.load( std::memory_order_relaxed ); - if( totalProgress == 0 ) - { - ImGui::CloseCurrentPopup(); - totalProgress = currProgress; - } - switch( currProgress ) - { - case tracy::LoadProgress::Initialization: - ImGui::TextUnformatted( "Initialization..." ); - break; - case tracy::LoadProgress::Locks: - ImGui::TextUnformatted( "Locks..." ); - break; - case tracy::LoadProgress::Messages: - ImGui::TextUnformatted( "Messages..." ); - break; - case tracy::LoadProgress::Zones: - ImGui::TextUnformatted( "CPU zones..." ); - break; - case tracy::LoadProgress::GpuZones: - ImGui::TextUnformatted( "GPU zones..." ); - break; - case tracy::LoadProgress::Plots: - ImGui::TextUnformatted( "Plots..." ); - break; - case tracy::LoadProgress::Memory: - ImGui::TextUnformatted( "Memory..." ); - break; - case tracy::LoadProgress::CallStacks: - ImGui::TextUnformatted( "Call stacks..." ); - break; - case tracy::LoadProgress::FrameImages: - ImGui::TextUnformatted( "Frame images..." ); - break; - case tracy::LoadProgress::ContextSwitches: - ImGui::TextUnformatted( "Context switches..." ); - break; - case tracy::LoadProgress::ContextSwitchesPerCpu: - ImGui::TextUnformatted( "CPU context switches..." ); - break; - default: - assert( false ); - break; - } - ImGui::ProgressBar( float( currProgress ) / totalProgress, ImVec2( 200 * dpiScale, 0 ) ); - - ImGui::TextUnformatted( "Progress..." ); - auto subTotal = progress.subTotal.load( std::memory_order_relaxed ); - auto subProgress = progress.subProgress.load( std::memory_order_relaxed ); - if( subTotal == 0 ) - { - ImGui::ProgressBar( 1.f, ImVec2( 200 * dpiScale, 0 ) ); - } - else - { - ImGui::ProgressBar( float( subProgress ) / subTotal, ImVec2( 200 * dpiScale, 0 ) ); - } - ImGui::EndPopup(); - } - switch( viewShutdown ) - { - case ViewShutdown::True: - ImGui::OpenPopup( "Capture cleanup..." ); - break; - case ViewShutdown::Join: - loadThread.join(); - viewShutdown = ViewShutdown::False; - break; - default: - break; - } - if( ImGui::BeginPopupModal( "Capture cleanup...", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) - { - if( viewShutdown != ViewShutdown::True ) ImGui::CloseCurrentPopup(); - tracy::TextCentered( ICON_FA_BROOM ); - time += io.DeltaTime; - tracy::DrawWaitingDots( time ); - ImGui::Text( "Please wait, cleanup is in progress" ); - ImGui::EndPopup(); - } - - // Rendering - ImGui::Render(); - glfwMakeContextCurrent(window); - glViewport(0, 0, display_w, display_h); - glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - glfwMakeContextCurrent(window); - glfwSwapBuffers(window); - + DrawContents(); if( !glfwGetWindowAttrib( window, GLFW_FOCUSED ) ) { std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); @@ -760,3 +351,415 @@ int main( int argc, char** argv ) return 0; } + +static void DrawContents() +{ + const ImVec4 clear_color = ImColor( 114, 144, 154 ); + + int display_w, display_h; + glfwGetFramebufferSize(s_glfwWindow, &display_w, &display_h); + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + if( !view ) + { + if( s_customTitle ) + { + s_customTitle = false; + glfwSetWindowTitle( s_glfwWindow, title ); + } + + const auto time = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count(); + if( !broadcastListen ) + { + broadcastListen = std::make_unique(); + if( !broadcastListen->Listen( port ) ) + { + broadcastListen.reset(); + } + } + else + { + tracy::IpAddress addr; + size_t len; + auto msg = broadcastListen->Read( len, addr ); + if( msg ) + { + assert( len <= sizeof( tracy::BroadcastMessage ) ); + tracy::BroadcastMessage bm; + memcpy( &bm, msg, len ); + + if( bm.broadcastVersion == tracy::BroadcastVersion ) + { + const uint32_t protoVer = bm.protocolVersion; + const auto procname = bm.programName; + const auto activeTime = bm.activeTime; + auto address = addr.GetText(); + + const auto ipNumerical = addr.GetNumber(); + auto it = clients.find( ipNumerical ); + if( it == clients.end() ) + { + std::string ip( address ); + resolvLock.lock(); + if( resolvMap.find( ip ) == resolvMap.end() ) + { + resolvMap.emplace( ip, ip ); + resolv.Query( ipNumerical, [ip] ( std::string&& name ) { + std::lock_guard lock( resolvLock ); + auto it = resolvMap.find( ip ); + assert( it != resolvMap.end() ); + std::swap( it->second, name ); + } ); + } + resolvLock.unlock(); + clients.emplace( addr.GetNumber(), ClientData { time, protoVer, activeTime, procname, std::move( ip ) } ); + } + else + { + it->second.time = time; + it->second.activeTime = activeTime; + if( it->second.protocolVersion != protoVer ) it->second.protocolVersion = protoVer; + if( strcmp( it->second.procName.c_str(), procname ) != 0 ) it->second.procName = procname; + } + } + } + auto it = clients.begin(); + while( it != clients.end() ) + { + const auto diff = time - it->second.time; + if( diff > 4000 ) // 4s + { + it = clients.erase( it ); + } + else + { + ++it; + } + } + } + + setlocale( LC_NUMERIC, "C" ); + auto& style = ImGui::GetStyle(); + style.Colors[ImGuiCol_WindowBg] = ImVec4( 0.129f, 0.137f, 0.11f, 1.f ); + ImGui::Begin( "Get started", nullptr, ImGuiWindowFlags_AlwaysAutoResize ); + char buf[128]; + sprintf( buf, "Tracy Profiler %i.%i.%i", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch ); + ImGui::PushFont( bigFont ); + tracy::TextCentered( buf ); + ImGui::PopFont(); + ImGui::Spacing(); + if( ImGui::Button( ICON_FA_BOOK " Manual" ) ) + { + OpenWebpage( "https://bitbucket.org/wolfpld/tracy/downloads/tracy.pdf" ); + } + ImGui::SameLine(); + if( ImGui::Button( ICON_FA_GLOBE_AMERICAS " Web" ) ) + { + OpenWebpage( "https://bitbucket.org/wolfpld/tracy" ); + } + ImGui::SameLine(); + if( ImGui::Button( ICON_FA_COMMENT " Chat" ) ) + { + OpenWebpage( "https://discord.gg/pk78auc" ); + } + ImGui::SameLine(); + if( ImGui::Button( ICON_FA_VIDEO " Tutorial" ) ) + { + ImGui::OpenPopup( "tutorial" ); + } + if( ImGui::BeginPopup( "tutorial" ) ) + { + if( ImGui::Selectable( ICON_FA_VIDEO " Introduction to the Tracy Profiler" ) ) + { + OpenWebpage( "https://www.youtube.com/watch?v=fB5B46lbapc" ); + } + if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.3" ) ) + { + OpenWebpage( "https://www.youtube.com/watch?v=3SXpDpDh2Uo" ); + } + if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.4" ) ) + { + OpenWebpage( "https://www.youtube.com/watch?v=eAkgkaO8B9o" ); + } + if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.5" ) ) + { + OpenWebpage( "https://www.youtube.com/watch?v=P6E7qLMmzTQ" ); + } + if( ImGui::Selectable( ICON_FA_VIDEO " New features in Tracy Profiler v0.6" ) ) + { + OpenWebpage( "https://www.youtube.com/watch?v=uJkrFgriuOo" ); + } + ImGui::EndPopup(); + } + ImGui::Separator(); + ImGui::TextUnformatted( "Client address" ); + bool connectClicked = false; + connectClicked |= ImGui::InputTextWithHint( "###connectaddress", "Enter address", addr, 1024, ImGuiInputTextFlags_EnterReturnsTrue ); + if( !connHistVec.empty() ) + { + ImGui::SameLine(); + if( ImGui::BeginCombo( "##frameCombo", nullptr, ImGuiComboFlags_NoPreview ) ) + { + int idxRemove = -1; + const auto sz = std::min( 5, connHistVec.size() ); + for( size_t i=0; ifirst; + if( ImGui::Selectable( str.c_str() ) ) + { + memcpy( addr, str.c_str(), str.size() + 1 ); + } + if( ImGui::IsItemHovered() && ImGui::IsKeyPressed( ImGui::GetKeyIndex( ImGuiKey_Delete ), false ) ) + { + idxRemove = (int)i; + } + } + if( idxRemove >= 0 ) + { + connHistMap.erase( connHistVec[idxRemove] ); + connHistVec = RebuildConnectionHistory( connHistMap ); + } + ImGui::EndCombo(); + } + } + connectClicked |= ImGui::Button( ICON_FA_WIFI " Connect" ); + if( connectClicked && *addr && !loadThread.joinable() ) + { + std::string addrStr( addr ); + auto it = connHistMap.find( addrStr ); + if( it != connHistMap.end() ) + { + it->second++; + } + else + { + connHistMap.emplace( std::move( addrStr ), 1 ); + } + connHistVec = RebuildConnectionHistory( connHistMap ); + + view = std::make_unique( addr, port, fixedWidth, smallFont, bigFont, SetWindowTitleCallback ); + } + ImGui::SameLine( 0, ImGui::GetFontSize() * 2 ); + if( ImGui::Button( ICON_FA_FOLDER_OPEN " Open saved trace" ) && !loadThread.joinable() ) + { + nfdchar_t* fn; + auto res = NFD_OpenDialog( "tracy", nullptr, &fn ); + if( res == NFD_OKAY ) + { + try + { + auto f = std::shared_ptr( tracy::FileRead::Open( fn ) ); + if( f ) + { + loadThread = std::thread( [f] { + try + { + view = std::make_unique( *f, fixedWidth, smallFont, bigFont, SetWindowTitleCallback ); + } + catch( const tracy::UnsupportedVersion& e ) + { + badVer.state = tracy::BadVersionState::UnsupportedVersion; + badVer.version = e.version; + } + catch( const tracy::LegacyVersion& e ) + { + badVer.state = tracy::BadVersionState::LegacyVersion; + badVer.version = e.version; + } + } ); + } + } + catch( const tracy::NotTracyDump& ) + { + badVer.state = tracy::BadVersionState::BadFile; + } + } + } + + if( badVer.state != tracy::BadVersionState::Ok ) + { + if( loadThread.joinable() ) { loadThread.join(); } + tracy::BadVersion( badVer ); + } + + if( !clients.empty() ) + { + ImGui::Separator(); + ImGui::TextUnformatted( "Discovered clients:" ); + ImGui::Separator(); + static bool widthSet = false; + ImGui::Columns( 3 ); + if( !widthSet ) + { + widthSet = true; + const auto w = ImGui::GetWindowWidth(); + ImGui::SetColumnWidth( 0, w * 0.35f ); + ImGui::SetColumnWidth( 1, w * 0.175f ); + ImGui::SetColumnWidth( 2, w * 0.425f ); + } + std::lock_guard lock( resolvLock ); + for( auto& v : clients ) + { + const bool badProto = v.second.protocolVersion != tracy::ProtocolVersion; + bool sel = false; + const auto& name = resolvMap.find( v.second.address ); + assert( name != resolvMap.end() ); + ImGuiSelectableFlags flags = ImGuiSelectableFlags_SpanAllColumns; + if( badProto ) flags |= ImGuiSelectableFlags_Disabled; + if( ImGui::Selectable( name->second.c_str(), &sel, flags ) && !loadThread.joinable() ) + { + view = std::make_unique( v.second.address.c_str(), port, fixedWidth, smallFont, bigFont, SetWindowTitleCallback ); + } + ImGui::NextColumn(); + const auto acttime = ( v.second.activeTime + ( time - v.second.time ) / 1000 ) * 1000000000ll; + if( badProto ) + { + tracy::TextDisabledUnformatted( tracy::TimeToString( acttime ) ); + } + else + { + ImGui::TextUnformatted( tracy::TimeToString( acttime ) ); + } + ImGui::NextColumn(); + if( badProto ) + { + tracy::TextDisabledUnformatted( v.second.procName.c_str() ); + } + else + { + ImGui::TextUnformatted( v.second.procName.c_str() ); + } + ImGui::NextColumn(); + } + ImGui::EndColumns(); + } + + ImGui::End(); + } + else + { + if( broadcastListen ) + { + broadcastListen.reset(); + clients.clear(); + } + if( loadThread.joinable() ) loadThread.join(); + view->NotifyRootWindowSize( display_w, display_h ); + if( !view->Draw() ) + { + viewShutdown = ViewShutdown::True; + loadThread = std::thread( [view = std::move( view )] () mutable { + view.reset(); + viewShutdown = ViewShutdown::Join; + } ); + } + } + auto& progress = tracy::Worker::GetLoadProgress(); + auto totalProgress = progress.total.load( std::memory_order_relaxed ); + if( totalProgress != 0 ) + { + ImGui::OpenPopup( "Loading trace..." ); + } + if( ImGui::BeginPopupModal( "Loading trace...", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) + { + tracy::TextCentered( ICON_FA_HOURGLASS_HALF ); + + animTime += ImGui::GetIO().DeltaTime; + tracy::DrawWaitingDots( animTime ); + + auto currProgress = progress.progress.load( std::memory_order_relaxed ); + if( totalProgress == 0 ) + { + ImGui::CloseCurrentPopup(); + totalProgress = currProgress; + } + switch( currProgress ) + { + case tracy::LoadProgress::Initialization: + ImGui::TextUnformatted( "Initialization..." ); + break; + case tracy::LoadProgress::Locks: + ImGui::TextUnformatted( "Locks..." ); + break; + case tracy::LoadProgress::Messages: + ImGui::TextUnformatted( "Messages..." ); + break; + case tracy::LoadProgress::Zones: + ImGui::TextUnformatted( "CPU zones..." ); + break; + case tracy::LoadProgress::GpuZones: + ImGui::TextUnformatted( "GPU zones..." ); + break; + case tracy::LoadProgress::Plots: + ImGui::TextUnformatted( "Plots..." ); + break; + case tracy::LoadProgress::Memory: + ImGui::TextUnformatted( "Memory..." ); + break; + case tracy::LoadProgress::CallStacks: + ImGui::TextUnformatted( "Call stacks..." ); + break; + case tracy::LoadProgress::FrameImages: + ImGui::TextUnformatted( "Frame images..." ); + break; + case tracy::LoadProgress::ContextSwitches: + ImGui::TextUnformatted( "Context switches..." ); + break; + case tracy::LoadProgress::ContextSwitchesPerCpu: + ImGui::TextUnformatted( "CPU context switches..." ); + break; + default: + assert( false ); + break; + } + ImGui::ProgressBar( float( currProgress ) / totalProgress, ImVec2( 200 * dpiScale, 0 ) ); + + ImGui::TextUnformatted( "Progress..." ); + auto subTotal = progress.subTotal.load( std::memory_order_relaxed ); + auto subProgress = progress.subProgress.load( std::memory_order_relaxed ); + if( subTotal == 0 ) + { + ImGui::ProgressBar( 1.f, ImVec2( 200 * dpiScale, 0 ) ); + } + else + { + ImGui::ProgressBar( float( subProgress ) / subTotal, ImVec2( 200 * dpiScale, 0 ) ); + } + ImGui::EndPopup(); + } + switch( viewShutdown ) + { + case ViewShutdown::True: + ImGui::OpenPopup( "Capture cleanup..." ); + break; + case ViewShutdown::Join: + loadThread.join(); + viewShutdown = ViewShutdown::False; + break; + default: + break; + } + if( ImGui::BeginPopupModal( "Capture cleanup...", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) ) + { + if( viewShutdown != ViewShutdown::True ) ImGui::CloseCurrentPopup(); + tracy::TextCentered( ICON_FA_BROOM ); + animTime += ImGui::GetIO().DeltaTime; + tracy::DrawWaitingDots( animTime ); + ImGui::Text( "Please wait, cleanup is in progress" ); + ImGui::EndPopup(); + } + + // Rendering + ImGui::Render(); + glfwMakeContextCurrent(s_glfwWindow); + glViewport(0, 0, display_w, display_h); + glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + glfwMakeContextCurrent(s_glfwWindow); + glfwSwapBuffers(s_glfwWindow); +}