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
|