File: delegated_ink_point_renderer_base.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (218 lines) | stat: -rw-r--r-- 8,398 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/viz/service/display/delegated_ink_point_renderer_base.h"

#include <algorithm>

#include "base/debug/dump_without_crashing.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/service/display/delegated_ink_trail_data.h"

namespace viz {

DelegatedInkPointRendererBase::DelegatedInkPointRendererBase() = default;
DelegatedInkPointRendererBase::~DelegatedInkPointRendererBase() = default;

void DelegatedInkPointRendererBase::InitMessagePipeline(
    mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver) {
  // The remote end of this pipeline exists on a per-tab basis, so if tab A
  // is using the feature and then tab B starts trying to use it, a new
  // PendingReceiver will arrive here while |receiver_| is still bound to the
  // remote in tab A. In this case, just reset |receiver_| so that tab A's
  // remote is unbound and bind the new receiver to use the feature in tab B.
  if (receiver_.is_bound()) {
    receiver_.reset();
    metadata_.reset();
    pointer_ids_.clear();
  }
  receiver_.Bind(std::move(receiver));
}

void DelegatedInkPointRendererBase::SetDelegatedInkMetadata(
    std::unique_ptr<gfx::DelegatedInkMetadata> metadata) {
  // Frame time is set later than everything else due to what is available
  // at time of creation, so confirm that it was actually set.
  CHECK_NE(metadata->frame_time(), base::TimeTicks());
  metadata_ = std::move(metadata);
  const bool metadata_is_new = previous_metadata_ != *metadata_;
  previous_metadata_ = *metadata_;

  TRACE_EVENT_WITH_FLOW1(
      "delegated_ink_trails",
      "DelegatedInkPointRendererBase::SetDelegatedInkMetadata",
      TRACE_ID_GLOBAL(metadata_->trace_id()), TRACE_EVENT_FLAG_FLOW_IN,
      "metadata", metadata_->ToString());

  // If we already have a cached pointer ID, check if the same pointer ID
  // matches the new metadata.
  if (pointer_id_.has_value() &&
      pointer_ids_[pointer_id_.value()].ContainsMatchingPoint(
          metadata_.get())) {
    if (metadata_is_new) {
      metadata_paint_time_ = pointer_ids_[pointer_id_.value()]
                                 .GetMatchingPoint(metadata_.get())
                                 .paint_timestamp();
    }
    return;
  }

  // If not, find the pointer ID that does match it, if any, and cache it.
  for (auto& it : pointer_ids_) {
    if (it.second.ContainsMatchingPoint(metadata_.get())) {
      pointer_id_ = it.first;
      metadata_paint_time_ =
          it.second.GetMatchingPoint(metadata_.get()).paint_timestamp();
      return;
    }
  }

  // If we aren't able to find any matching point, set the pointer ID to null
  // so that FilterPoints and PredictPoints can early out.
  pointer_id_ = std::nullopt;
}

void DelegatedInkPointRendererBase::ResetPoints() {
  CHECK(!metadata_);
  pointer_ids_.clear();
  pointer_id_.reset();
}

std::vector<gfx::DelegatedInkPoint>
DelegatedInkPointRendererBase::FilterPoints() {
  if (pointer_ids_.empty()) {
    return {};
  }

  CHECK(metadata_);

  // Any stored point with a timestamp earlier than the metadata's has already
  // been drawn as part of the ink stroke and therefore should not be part of
  // the delegated ink trail. Do this before checking if |pointer_id_| is valid
  // because it helps manage the number of DelegatedInkPoints that are being
  // stored and isn't dependent on |pointer_id_| at all.
  for (auto& it : pointer_ids_) {
    it.second.ErasePointsOlderThanMetadata(metadata_.get());
  }

  // TODO(crbug.com/40118757): Add additional filtering to prevent points in
  // |points_| from having a timestamp that is far ahead of |metadata_|'s
  // timestamp. This could occur if the renderer stalls before sending a
  // metadata while the browser continues to pump points through to viz. Then
  // when the renderer starts back up again, the metadata it sends may be
  // significantly older than the points stored here, resulting in a long
  // possibly incorrect trail if the max number of points to store was reached.

  // If no point with any pointer id exactly matches the metadata, then we can't
  // confirm which set of points to use for the delegated ink trail, so just
  // return an empty vector so that nothing will be drawn. This happens most
  // often at the beginning of delegated ink trail use. The metadata is created
  // using a PointerEvent earlier than any DelegatedInkPoint is created,
  // resulting in the metadata having an earlier timestamp and a point that
  // doesn't match anything that is sent here from viz. Even if only a single
  // pointer ID is in use, we can't know with any certainty what happened
  // between the metadata point and the earliest DelegatedInkPoint we have, so
  // we choose to just not draw anything.
  if (!pointer_id_.has_value()) {
    return {};
  }

  DelegatedInkTrailData& trail_data = pointer_ids_[pointer_id_.value()];

  // Make sure the metrics handler is provided the new real events to accurately
  // measure the prediction later.
  trail_data.UpdateMetrics(metadata_.get());

  // Any remaining points must be the points that should be part of the
  // delegated ink trail
  std::vector<gfx::DelegatedInkPoint> points_to_draw;
  for (const auto& [_, point] : trail_data.GetPoints()) {
    points_to_draw.emplace_back(point);
    TRACE_EVENT_WITH_FLOW1("delegated_ink_trails", "Filtering to draw point",
                           TRACE_ID_GLOBAL(point.trace_id()),
                           TRACE_EVENT_FLAG_FLOW_IN, "point", point.ToString());
  }

  if (!points_to_draw.front().MatchesDelegatedInkMetadata(metadata_.get())) {
    base::debug::DumpWithoutCrashing();
  }

  return points_to_draw;
}

std::optional<AggregatedRenderPassId>
DelegatedInkPointRendererBase::GetLatestMetadataRenderPassId() const {
  if (metadata_) {
    return AggregatedRenderPassId::FromUnsafeValue(metadata_->render_pass_id());
  }
  return std::nullopt;
}

void DelegatedInkPointRendererBase::PredictPoints(
    std::vector<gfx::DelegatedInkPoint>* ink_points_to_draw) {
  DCHECK(metadata_);

  if (!pointer_id_.has_value() ||
      static_cast<int>(ink_points_to_draw->size()) == 0)
    return;

  pointer_ids_[pointer_id_.value()].PredictPoints(ink_points_to_draw,
                                                  metadata_.get());
}

void DelegatedInkPointRendererBase::ResetPrediction() {
  for (auto& it : pointer_ids_)
    it.second.Reset();
  TRACE_EVENT_INSTANT0("delegated_ink_trails",
                       "Delegated ink prediction reset.",
                       TRACE_EVENT_SCOPE_THREAD);
}

void DelegatedInkPointRendererBase::ReportPointsDrawn() {
  const base::TimeTicks now = base::TimeTicks::Now();
  // If there is a point that matches the metadata and the histogram has not yet
  // been fired, then this is the first frame that the metadata point will be
  // recorded by `updateInkTrailStartPoint`.
  if (metadata_paint_time_.has_value()) {
    base::UmaHistogramCustomTimes(
        "Renderer.DelegatedInkTrail.Skia.TimeFromDelegatedInkToApiPaint",
        now - metadata_paint_time_.value(), base::Milliseconds(1),
        base::Seconds(1), 50);
    metadata_paint_time_ = std::nullopt;
  }

  if (!pointer_id_.has_value()) {
    return;
  }
  CHECK(pointer_ids_.contains(pointer_id_.value()));
  auto& points_trail = pointer_ids_.at(pointer_id_.value()).GetPoints();
  base::UmaHistogramCounts100(
      "Renderer.DelegatedInkTrail.Skia.OutstandingPointsToDraw",
      points_trail.size());

  for (auto& [_, point] : points_trail) {
    UMA_HISTOGRAM_TIMES(
        "Renderer.DelegatedInkTrail.Skia.TimeToDrawPointsMillis",
        now - point.timestamp());
    if (!point.paint_timestamp().has_value()) {
      point.set_paint_timestamp(now);
    }
  }
}

void DelegatedInkPointRendererBase::StoreDelegatedInkPoint(
    const gfx::DelegatedInkPoint& point) {
  TRACE_EVENT_WITH_FLOW1(
      "delegated_ink_trails",
      "DelegatedInkPointRendererImpl::StoreDelegatedInkPoint",
      TRACE_ID_GLOBAL(point.trace_id()),
      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "point",
      point.ToString());

  pointer_ids_[point.pointer_id()].AddPoint(point);
}

}  // namespace viz