0

Exo: Pass trace ID across wayland to track frame submission.

This CL extends surface_augmenter wayland protocol to
support passing trace ID from wayland clients to the server
side to track frame submission, so that we can connect the
event flows of the two sides and show a complete picture of
graphics pipeline in Perfetto.

This is the server-side impl. The client side will be in a
separate CL.

PERFETTO_TESTS=`autoninja -C out_linux_lacros/Release perfetto_diff_tests && out_linux_lacros/Release/bin/run_perfetto_diff_tests`

Bug: 1524160
Change-Id: I83aaa2f0b020d8e60954e6b477ce0990005cf271
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5259564
Commit-Queue: Yuzhu Shen <yzshen@chromium.org>
Reviewed-by: Stephen Nusko <nuskos@chromium.org>
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1257243}
This commit is contained in:
Yuzhu Shen
2024-02-07 09:01:02 +00:00
committed by Chromium LUCI CQ
parent e899ff8f20
commit 5606082990
8 changed files with 124 additions and 12 deletions

@ -1386,6 +1386,14 @@ message ChromeGraphicsPipeline {
STEP_BUFFER_SWAP_POST_SUBMIT = 12;
STEP_FINISH_BUFFER_SWAP = 13;
STEP_SWAP_BUFFERS_ACK = 14;
// Frame submission stages when Exo (Wayland server implementation in Ash
// browser process) is involved. Wayland clients (such as Lacros or ARC++)
// submit visual contents via Wayland surface commits, with which Exo
// constructs compositor frames and forwards to Ash Viz.
STEP_EXO_CONSTRUCT_COMPOSITOR_FRAME = 15;
STEP_EXO_SUBMIT_COMPOSITOR_FRAME = 16;
STEP_EXO_DISCARD_COMPOSITOR_FRAME = 17;
}
enum FrameSkippedReason {
SKIPPED_REASON_UNKNOWN = 0;

@ -6,6 +6,7 @@
#include "base/containers/contains.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/typed_macros.h"
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "components/exo/surface_tree_host.h"
#include "components/viz/common/frame_timing_details.h"
@ -387,6 +388,20 @@ void LayerTreeFrameSinkHolder::DiscardCachedFrame(
cached_frame_->metadata.frame_token);
}
const int64_t client_frame_trace_id =
cached_frame_->metadata.begin_frame_ack.trace_id;
if (client_frame_trace_id != -1) {
TRACE_EVENT_INSTANT(
"viz,benchmark,graphics.pipeline", "Graphics.Pipeline",
perfetto::Flow::Global(client_frame_trace_id),
[client_frame_trace_id](perfetto::EventContext ctx) {
auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
auto* data = event->set_chrome_graphics_pipeline();
data->set_step(perfetto::protos::pbzero::ChromeGraphicsPipeline::
StepName::STEP_EXO_DISCARD_COMPOSITOR_FRAME);
data->set_display_trace_id(client_frame_trace_id);
});
}
cached_frame_.reset();
frame_timing_history_->FrameDiscarded();
@ -470,18 +485,39 @@ void LayerTreeFrameSinkHolder::UpdateSubmitFrameTimer() {
void LayerTreeFrameSinkHolder::ProcessFirstPendingBeginFrame(
viz::CompositorFrame* frame) {
// The client-side frame trace ID, if available, is temporarily stored in
// the frame's BeginFrameAck struct. Extract it before populating
// BeginFrameAck.
const int64_t client_frame_trace_id =
frame->metadata.begin_frame_ack.trace_id;
// If there are not-yet-handled BeginFrames requests from the remote side,
// use `frame` as response to the earliest one.
if (!pending_begin_frames_.empty()) {
frame->metadata.begin_frame_ack =
pending_begin_frames_.front().begin_frame_ack;
pending_begin_frames_.pop();
return;
} else {
// Submit an unsolicited frame.
frame->metadata.begin_frame_ack =
viz::BeginFrameAck::CreateManualAckWithDamage();
}
// Submit an unsolicited frame.
frame->metadata.begin_frame_ack =
viz::BeginFrameAck::CreateManualAckWithDamage();
if (client_frame_trace_id != -1) {
// Use both the ID from the client-side frame submission and the ID from the
// BeginFrame request to connect the two flows.
TRACE_EVENT_INSTANT(
"viz,benchmark,graphics.pipeline", "Graphics.Pipeline",
perfetto::Flow::Global(client_frame_trace_id),
perfetto::Flow::Global(frame->metadata.begin_frame_ack.trace_id),
[client_frame_trace_id](perfetto::EventContext ctx) {
auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
auto* data = event->set_chrome_graphics_pipeline();
data->set_step(perfetto::protos::pbzero::ChromeGraphicsPipeline::
StepName::STEP_EXO_SUBMIT_COMPOSITOR_FRAME);
data->set_display_trace_id(client_frame_trace_id);
});
}
}
bool LayerTreeFrameSinkHolder::ShouldSubmitFrameNow() const {

@ -647,6 +647,10 @@ void Surface::SetClipRect(const std::optional<gfx::RectF>& clip_rect) {
pending_state_.clip_rect_is_parent_coordinates = false;
}
void Surface::SetFrameTraceId(int64_t frame_trace_id) {
pending_state_.frame_trace_id = frame_trace_id;
}
void Surface::SetClipRectOnParentSurface(
const std::optional<gfx::RectF>& clip_rect) {
TRACE_EVENT1("exo", "Surface::SetClipRectOnParentSurface", "clip_rect",
@ -947,6 +951,9 @@ void Surface::Commit() {
cached_state_.presentation_callbacks.end(),
pending_state_.presentation_callbacks);
cached_state_.frame_trace_id = pending_state_.frame_trace_id;
pending_state_.frame_trace_id = -1;
if (delegate_)
delegate_->OnSurfaceCommit();
else
@ -1166,6 +1173,9 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
state_.damage.Intersect(output_rect);
}
cached_state_.damage.Clear();
state_.frame_trace_id = cached_state_.frame_trace_id;
cached_state_.frame_trace_id = -1;
}
surface_hierarchy_content_bounds_ =

@ -206,6 +206,10 @@ class Surface final : public ui::PropertyHandler {
// Sets the surface's clip rectangle.
void SetClipRect(const std::optional<gfx::RectF>& clip_rect);
// Sets the trace ID for tracking frame submission, which is used for the next
// surface commit.
void SetFrameTraceId(int64_t frame_trace_id);
// Sets the surface's clip rectangle on parent surface coordinates.
// TODO(crbug.com/1457446): Remove this.
void SetClipRectOnParentSurface(const std::optional<gfx::RectF>& clip_rect);
@ -496,6 +500,8 @@ class Surface final : public ui::PropertyHandler {
// Returns the buffer scale of the last committed buffer.
float GetBufferScale() const { return state_.basic_state.buffer_scale; }
int64_t GetFrameTraceId() const { return state_.frame_trace_id; }
// Returns the last committed buffer.
Buffer* GetBuffer();
@ -621,6 +627,10 @@ class Surface final : public ui::PropertyHandler {
// for subsurfaces, and doesn't apply to children of this surface.
// Persisted between commits.
gfx::Transform surface_transform;
// Trace ID for tracking frame submission.
// Not persisted between commits.
int64_t frame_trace_id;
};
friend class subtle::PropertyHelper;

@ -335,6 +335,21 @@ void SurfaceTreeHost::SubmitCompositorFrame() {
<< ", StartupId=" << (startup_id ? *startup_id : "''");
}
const int64_t frame_trace_id = root_surface_->GetFrameTraceId();
if (frame_trace_id != -1) {
frame.metadata.begin_frame_ack.trace_id = frame_trace_id;
TRACE_EVENT_INSTANT(
"viz,benchmark,graphics.pipeline", "Graphics.Pipeline",
perfetto::Flow::Global(frame_trace_id),
[frame_trace_id](perfetto::EventContext ctx) {
auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
auto* data = event->set_chrome_graphics_pipeline();
data->set_step(perfetto::protos::pbzero::ChromeGraphicsPipeline::
StepName::STEP_EXO_CONSTRUCT_COMPOSITOR_FRAME);
data->set_display_trace_id(frame_trace_id);
});
}
std::list<Surface::FrameCallback> current_frame_callbacks;
PresentationCallbacks presentation_callbacks;
root_surface_->AppendSurfaceHierarchyCallbacks(&current_frame_callbacks,

@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
<interface name="surface_augmenter" version="10">
<interface name="surface_augmenter" version="11">
<description summary="surface composition delegation">
The global interface exposing surface delegated composition
capabilities is used to instantiate an interface extension for a
@ -89,7 +89,7 @@
</request>
</interface>
<interface name="augmented_surface" version="10">
<interface name="augmented_surface" version="11">
<description summary="delegate composition of a wl_surface">
An additional interface to a wl_surface object, which allows the
client to specify the delegated composition of the surface
@ -248,11 +248,23 @@
<!-- Version 10 additions -->
<!-- CAUTION: Use Version 11 as a next since version.
<!--
This version updates the inner implementation of surface coordinate.
No protocol is added for this version.
-->
<!-- Version 11 additions -->
<request name="set_frame_trace_id" since="11">
<description summary="sets a trace ID for tracking frame submission flow">
This sets a trace ID to connect the frame submission trace event flow at
the client and the server side.
This state is double-buffered, and is applied on the next
wl_surface.commit.
</description>
<arg name="id_hi" type="uint" summary="high 32 bits of the trace ID"/>
<arg name="id_lo" type="uint" summary="low 32 bits of the trace ID"/>
</request>
</interface>
<interface name="augmented_sub_surface" version="5">

@ -95,6 +95,10 @@ class AugmentedSurface : public SurfaceObserver {
surface_->SetClipRect(clip_rect);
}
void SetFrameTraceId(int64_t frame_trace_id) {
surface_->SetFrameTraceId(frame_trace_id);
}
// SurfaceObserver:
void OnSurfaceDestroying(Surface* surface) override {
surface->RemoveSurfaceObserver(this);
@ -210,6 +214,25 @@ void augmented_surface_set_clip_rect(wl_client* client,
wl_fixed_to_double(height));
}
void augmented_surface_set_frame_trace_id(wl_client* client,
wl_resource* resource,
uint32_t id_hi,
uint32_t id_lo) {
base::CheckedNumeric<int64_t> id(id_hi);
id <<= 32;
id += id_lo;
if (!id.IsValid()) {
wl_resource_post_error(
resource, AUGMENTED_SURFACE_ERROR_BAD_VALUE,
"The frame trace ID cannot be converted to a valid int64_t (%u, %u)",
id_hi, id_lo);
return;
}
GetUserDataAs<AugmentedSurface>(resource)->SetFrameTraceId(id.ValueOrDie());
}
const struct augmented_surface_interface augmented_implementation = {
augmented_surface_destroy,
augmented_surface_set_corners_DEPRECATED,
@ -219,6 +242,7 @@ const struct augmented_surface_interface augmented_implementation = {
augmented_surface_set_trusted_damage,
augmented_surface_set_rounded_corners_clip_bounds,
augmented_surface_set_clip_rect,
augmented_surface_set_frame_trace_id,
};
////////////////////////////////////////////////////////////////////////////////

@ -11,12 +11,9 @@
namespace exo::wayland {
// Clients at version 8 think clip rect is in parent surface's space, while
// clients at version 9 or above think it's in local surface's space.
// Unfortunately, clipping in version 9 is implemented incorrectly. It has been
// fixed in version 10, so use version 10 instead.
// version: 11
constexpr uint32_t kSurfaceAugmenterVersion =
AUGMENTED_SURFACE_SET_CLIP_RECT_SINCE_VERSION + 2;
AUGMENTED_SURFACE_SET_FRAME_TRACE_ID_SINCE_VERSION;
void bind_surface_augmenter(wl_client* client,
void* data,