Skip to content

Commit 9bf450e

Browse files
Profiler Teamcopybara-github
authored andcommitted
Project import generated by Copybara
PiperOrigin-RevId: 837004373
1 parent 81acd69 commit 9bf450e

File tree

8 files changed

+172
-17
lines changed

8 files changed

+172
-17
lines changed

frontend/app/components/trace_viewer_v2/color/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ cc_library(
1616
"//third_party/dear_imgui",
1717
"//util/hash:highway_fingerprint",
1818
"@com_google_absl//absl/base:no_destructor",
19-
"@com_google_absl//absl/hash",
2019
"@com_google_absl//absl/strings",
2120
],
2221
)

frontend/app/components/trace_viewer_v2/color/color_generator.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ namespace traceviewer {
1313
namespace {
1414

1515
static constexpr ImU32 event_colors[] = {
16-
kMaterialPurple70,
17-
kMaterialGreen80,
18-
kMaterialBlue80,
19-
kMaterialYellow90,
16+
kPurple70,
17+
kGreen80,
18+
kBlue80,
19+
kYellow90,
2020
};
2121

2222
// Generates colors based on string IDs.

frontend/app/components/trace_viewer_v2/color/colors.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,25 @@ namespace traceviewer {
1111
//
1212
// For example, to get the color #C597FF (RR=C5, GG=97, BB=FF), the
1313
// ImU32 value is defined as 0xFF_FF97C5 (AA=FF, BB=FF, GG=97, RR=C5).
14-
//
15-
// These colors are from the Material Design color palette:
14+
15+
// Static palette:
1616
// go/keep-sorted start
1717
// Blue 80: #A1C9FF
18-
inline constexpr ImU32 kMaterialBlue80 = 0xFFFFC9A1;
18+
inline constexpr ImU32 kBlue80 = 0xFFFFC9A1;
1919
// Green 80: #80DA88
20-
inline constexpr ImU32 kMaterialGreen80 = 0xFF88DA80;
20+
inline constexpr ImU32 kGreen80 = 0xFF88DA80;
2121
// Purple 70: #C597FF
22-
inline constexpr ImU32 kMaterialPurple70 = 0xFFFF97C5;
22+
inline constexpr ImU32 kPurple70 = 0xFFFF97C5;
2323
// Yellow 90: #FFE07C
24-
inline constexpr ImU32 kMaterialYellow90 = 0xFF7CE0FF;
24+
inline constexpr ImU32 kYellow90 = 0xFF7CE0FF;
25+
// go/keep-sorted end
26+
27+
// Baseline palette:
28+
// go/keep-sorted start
29+
// Baseline Primary: #0B57D0
30+
inline constexpr ImU32 kPrimary40 = 0xFFD0570B;
31+
// Baseline Secondary: #C2E7FF
32+
inline constexpr ImU32 kSecondary90 = 0xFFFFE7C2;
2533
// go/keep-sorted end
2634

2735
} // namespace traceviewer

frontend/app/components/trace_viewer_v2/timeline/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ cc_library(
4141
],
4242
deps = [
4343
":constants",
44+
":draw_utils",
4445
":time_range",
4546
"//third_party/dear_imgui",
4647
"@com_google_absl//absl/base:nullability",
@@ -90,6 +91,17 @@ cc_library(
9091
],
9192
)
9293

94+
cc_library(
95+
name = "draw_utils",
96+
srcs = ["draw_utils.cc"],
97+
hdrs = ["draw_utils.h"],
98+
deps = [
99+
":constants",
100+
"//third_party/dear_imgui",
101+
"@org_xprof//frontend/app/components/trace_viewer_v2/color:colors",
102+
],
103+
)
104+
93105
cc_test(
94106
name = "data_provider_test",
95107
srcs = ["data_provider_test.cc"],
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include "xprof/frontend/app/components/trace_viewer_v2/timeline/draw_utils.h"
2+
3+
#include <algorithm>
4+
#include <cmath>
5+
6+
#include "xprof/frontend/app/components/trace_viewer_v2/color/colors.h"
7+
#include "xprof/frontend/app/components/trace_viewer_v2/timeline/constants.h"
8+
#include "third_party/dear_imgui/imgui.h"
9+
10+
namespace traceviewer {
11+
12+
namespace {
13+
14+
// GM3-style indefinite linear progress indicator constants.
15+
// The width of the progress bar as a ratio of the viewport width.
16+
constexpr float kProgressBarWidthRatio = 0.4f;
17+
constexpr Pixel kProgressBarHeight = 4.0f;
18+
// The duration in seconds for one full animation cycle of the progress bar.
19+
constexpr float kAnimationDuration = 3.0f;
20+
// The gap in pixels between the primary and secondary indicators.
21+
constexpr Pixel kProgressBarGap = 4.0f;
22+
// A scaling factor used in easing calculations for animation.
23+
constexpr float kProgressScale = 2.0f;
24+
constexpr Pixel kTextOffsetY = 16.0f;
25+
26+
// Draws a "Loading data..." text message centered below the progress bar.
27+
void DrawLoadingText(const ImGuiViewport* viewport) {
28+
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
29+
if (!draw_list) return;
30+
31+
const char* text = "Loading data...";
32+
const ImVec2 text_size = ImGui::CalcTextSize(text);
33+
const ImVec2 center = viewport->GetCenter();
34+
35+
const float text_x = center.x - text_size.x / 2.0f;
36+
// Position text below the progress bar. The progress bar's center is at
37+
// viewport->GetCenter().y.
38+
const float text_y = center.y + kProgressBarHeight / 2.0f + kTextOffsetY;
39+
40+
draw_list->AddText(ImVec2(text_x, text_y), kBlackColor, text);
41+
}
42+
43+
} // namespace
44+
45+
// Draws a loading indicator in the center of the viewport.
46+
void DrawLoadingIndicator(const ImGuiViewport* viewport) {
47+
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
48+
if (!draw_list) return;
49+
50+
const Pixel kProgressBarCornerRadius = kProgressBarHeight / 2.0f;
51+
const Pixel progress_bar_width = viewport->Size.x * kProgressBarWidthRatio;
52+
53+
const ImVec2 center = viewport->GetCenter();
54+
const Pixel start_x = center.x - progress_bar_width / 2.0f;
55+
const Pixel end_x = center.x + progress_bar_width / 2.0f;
56+
const Pixel y = center.y - kProgressBarHeight / 2.0f;
57+
58+
const float time = static_cast<float>(ImGui::GetTime());
59+
const float cycle_progress =
60+
fmod(time, kAnimationDuration) / kAnimationDuration;
61+
62+
// The animation of the primary progress bar is defined by the movement of its
63+
// head (right side) and tail (left side). The head moves with an ease-out
64+
// curve, starting fast and slowing down, while the tail moves linearly. This
65+
// creates the effect of the bar first growing in width and then shrinking as
66+
// the tail catches up to the head.
67+
68+
// Quadratic ease-out for the head of the bar.
69+
const float head_progress =
70+
kProgressScale * cycle_progress * (kProgressScale - cycle_progress);
71+
// Linear progress for the tail of the bar.
72+
const float tail_progress = kProgressScale * cycle_progress;
73+
74+
const Pixel primary_start = start_x + progress_bar_width * tail_progress;
75+
const Pixel primary_end = start_x + progress_bar_width * head_progress;
76+
77+
// Draw the two secondary segments and one primary segment, with gaps.
78+
// All segments are clipped to the progress bar's bounds.
79+
// Something like this:
80+
// (-----s1-----) (--p--) (-----s2-----)
81+
// ^ gap ^
82+
const Pixel s1_start = start_x;
83+
const Pixel s1_end = std::min(primary_start - kProgressBarGap, end_x);
84+
if (s1_start < s1_end) {
85+
draw_list->AddRectFilled(
86+
ImVec2(s1_start, y), ImVec2(s1_end, y + kProgressBarHeight),
87+
kSecondary90, kProgressBarCornerRadius, ImDrawFlags_RoundCornersAll);
88+
}
89+
90+
const Pixel p_start = std::max(primary_start, start_x);
91+
const Pixel p_end = std::min(primary_end, end_x);
92+
if (p_start < p_end) {
93+
draw_list->AddRectFilled(
94+
ImVec2(p_start, y), ImVec2(p_end, y + kProgressBarHeight), kPrimary40,
95+
kProgressBarCornerRadius, ImDrawFlags_RoundCornersAll);
96+
}
97+
98+
const Pixel s2_start = std::max(primary_end + kProgressBarGap, start_x);
99+
const Pixel s2_end = end_x;
100+
if (s2_start < s2_end) {
101+
draw_list->AddRectFilled(
102+
ImVec2(s2_start, y), ImVec2(s2_end, y + kProgressBarHeight),
103+
kSecondary90, kProgressBarCornerRadius, ImDrawFlags_RoundCornersAll);
104+
}
105+
106+
DrawLoadingText(viewport);
107+
}
108+
109+
} // namespace traceviewer
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef PERFTOOLS_ACCELERATORS_XPROF_FRONTEND_APP_COMPONENTS_TRACE_VIEWER_V2_TIMELINE_DRAW_UTILS_H_
2+
#define PERFTOOLS_ACCELERATORS_XPROF_FRONTEND_APP_COMPONENTS_TRACE_VIEWER_V2_TIMELINE_DRAW_UTILS_H_
3+
4+
#include "third_party/dear_imgui/imgui.h"
5+
6+
namespace traceviewer {
7+
8+
// Draws a loading indicator in the center of the viewport.
9+
void DrawLoadingIndicator(const ImGuiViewport* viewport);
10+
11+
} // namespace traceviewer
12+
13+
#endif // PERFTOOLS_ACCELERATORS_XPROF_FRONTEND_APP_COMPONENTS_TRACE_VIEWER_V2_TIMELINE_DRAW_UTILS_H_

frontend/app/components/trace_viewer_v2/timeline/timeline.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "xprof/frontend/app/components/trace_viewer_v2/event_data.h"
1111
#include "xprof/frontend/app/components/trace_viewer_v2/helper/time_formatter.h"
1212
#include "xprof/frontend/app/components/trace_viewer_v2/timeline/constants.h"
13+
#include "xprof/frontend/app/components/trace_viewer_v2/timeline/draw_utils.h"
1314
#include "xprof/frontend/app/components/trace_viewer_v2/timeline/time_range.h"
1415
#include "xprof/frontend/app/components/trace_viewer_v2/trace_helper/trace_event.h"
1516
#include "absl/base/nullability.h"
@@ -49,9 +50,6 @@ void Timeline::SetVisibleRange(const TimeRange& range, bool animate) {
4950
}
5051

5152
void Timeline::Draw() {
52-
if (timeline_data_.groups.empty()) {
53-
return;
54-
}
5553
event_clicked_this_frame_ = false;
5654

5755
const ImGuiViewport* viewport = ImGui::GetMainViewport();
@@ -61,6 +59,10 @@ void Timeline::Draw() {
6159
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.f);
6260
ImGui::Begin("Timeline viewer", nullptr, kImGuiWindowFlags);
6361

62+
if (timeline_data_.groups.empty()) {
63+
DrawLoadingIndicator(viewport);
64+
}
65+
6466
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
6567

6668
const Pixel timeline_width =

frontend/app/components/trace_viewer_v2/timeline/timeline_test.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,12 +1066,24 @@ TEST_F(RealTimelineImGuiFixture, ClickEmptyAreaWhenNoEventSelectedDoesNothing) {
10661066
EXPECT_FALSE(callback_called);
10671067
}
10681068

1069-
TEST_F(RealTimelineImGuiFixture, NoDrawIfTimelineDataIsEmpty) {
1069+
TEST_F(RealTimelineImGuiFixture,
1070+
DrawsLoadingAnimationWhenTimelineDataIsEmpty) {
10701071
timeline_.set_timeline_data({});
10711072

1072-
SimulateFrame();
1073+
// We don't use SimulateFrame() here because we need to inspect the draw list
1074+
// before ImGui::EndFrame() is called.
1075+
ImGui::NewFrame();
1076+
timeline_.Draw();
1077+
1078+
EXPECT_NE(ImGui::FindWindowByName("Timeline viewer"), nullptr);
1079+
1080+
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
1081+
1082+
ASSERT_NE(draw_list, nullptr);
1083+
// The loading animation should be drawn to the foreground draw list.
1084+
EXPECT_FALSE(draw_list->VtxBuffer.empty());
10731085

1074-
EXPECT_EQ(ImGui::FindWindowByName("Timeline viewer"), nullptr);
1086+
ImGui::EndFrame();
10751087
}
10761088

10771089
TEST_F(RealTimelineImGuiFixture, PanLeftBeyondDataRangeShouldBeConstrained) {

0 commit comments

Comments
 (0)