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 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_MANAGER_H_
#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_MANAGER_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/feature_list.h"
#include "base/features.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/surfaces/surface_observer.h"
#include "components/viz/service/surfaces/surface_reference.h"
#if DCHECK_IS_ON()
#include <iosfwd>
#include <string>
#endif
namespace base {
class TickClock;
} // namespace base
namespace viz {
class Surface;
class SurfaceAllocationGroup;
class SurfaceClient;
class SurfaceManagerDelegate;
class SurfaceRange;
class VIZ_SERVICE_EXPORT SurfaceManager {
public:
SurfaceManager(SurfaceManagerDelegate* delegate,
std::optional<uint32_t> activation_deadline_in_frames,
size_t max_uncommitted_frames);
SurfaceManager(const SurfaceManager&) = delete;
SurfaceManager& operator=(const SurfaceManager&) = delete;
~SurfaceManager();
#if DCHECK_IS_ON()
// Returns a string representation of all reachable surface references.
std::string SurfaceReferencesToString();
#endif
// Sets an alternative system default frame activation deadline for unit
// tests. std::nullopt indicates no deadline (in other words, an unlimited
// deadline).
void SetActivationDeadlineInFramesForTesting(
std::optional<uint32_t> deadline);
std::optional<uint32_t> activation_deadline_in_frames() const {
return activation_deadline_in_frames_;
}
// Sets an alternative base::TickClock to pass into surfaces for surface
// synchronization deadlines. This allows unit tests to mock the wall clock.
void SetTickClockForTesting(const base::TickClock* tick_clock);
// Returns the base::TickClock used to set surface synchronization deadlines.
const base::TickClock* tick_clock() { return tick_clock_; }
// Creates a Surface for the given SurfaceClient. The surface will be
// destroyed when MarkSurfaceForDestruction is called, all of its destruction
// dependencies are satisfied, and it is not reachable from the root surface.
// A temporary reference will be added to the new Surface.
Surface* CreateSurface(base::WeakPtr<SurfaceClient> surface_client,
const SurfaceInfo& surface_info,
const SurfaceId& pending_copy_surface_id);
// Marks |surface_id| for destruction. The surface will get destroyed when
// it's not reachable from the root or any other surface that is not marked
// for destruction.
void MarkSurfaceForDestruction(const SurfaceId& surface_id);
// Returns a Surface corresponding to the provided |surface_id|.
Surface* GetSurfaceForId(const SurfaceId& surface_id) const;
void AddObserver(SurfaceObserver* obs) { observer_list_.AddObserver(obs); }
void RemoveObserver(SurfaceObserver* obs) {
observer_list_.RemoveObserver(obs);
}
// Called when a Surface is modified, e.g. when a CompositorFrame is
// activated, its producer confirms that no CompositorFrame will be submitted
// in response to a BeginFrame, or a CopyOutputRequest is issued.
//
// |ack.sequence_number| is only valid if called in response to a BeginFrame.
bool SurfaceModified(const SurfaceId& surface_id,
const BeginFrameAck& ack,
SurfaceObserver::HandleInteraction handle_interaction);
// Called when a surface has an active frame for the first time.
void FirstSurfaceActivation(const SurfaceInfo& surface_info);
// Called when there is new frame in uncommitted queue of the surface.
void OnSurfaceHasNewUncommittedFrame(Surface* surface);
// Called when a CompositorFrame within |surface| has activated.
void SurfaceActivated(Surface* surface);
// Called when |surface| is being destroyed.
void SurfaceDestroyed(Surface* surface);
// Called when a Surface's CompositorFrame producer has received a BeginFrame
// and, thus, is expected to produce damage soon.
void SurfaceDamageExpected(const SurfaceId& surface_id,
const BeginFrameArgs& args);
// Invalidate a frame_sink_id that might still have associated sequences,
// possibly because a renderer process has crashed.
void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
// Returns the top level root SurfaceId. Surfaces that are not reachable
// from the top level root may be garbage collected. It will not be a valid
// SurfaceId and will never correspond to a surface.
const SurfaceId& GetRootSurfaceId() const;
// Returns SurfaceIds of currently alive Surfaces. This may include ids of
// Surfaces that are about to be destroyed.
std::vector<SurfaceId> GetCreatedSurfaceIds() const;
// Adds all surface references in |references|. This will remove any temporary
// references for child surface in a surface reference.
void AddSurfaceReferences(const std::vector<SurfaceReference>& references);
// Removes all surface references in |references| then runs garbage
// collection to delete unreachable surfaces.
void RemoveSurfaceReferences(const std::vector<SurfaceReference>& references);
// Garbage collects all destroyed surfaces that aren't live.
void GarbageCollectSurfaces();
// Returns all surfaces referenced by parent |surface_id|. Will return an
// empty set if |surface_id| is unknown or has no references.
const base::flat_set<SurfaceId>& GetSurfacesReferencedByParent(
const SurfaceId& surface_id) const;
// Returns all surfaces that have a reference to child |surface_id|. Will
// return an empty set if |surface_id| is unknown or has no references to it.
base::flat_set<SurfaceId> GetSurfacesThatReferenceChildForTesting(
const SurfaceId& surface_id) const;
// Gets the earliest timestamp when the surface with ID `surface_id` gets
// embedded through `AddSurfaceReferences()`, if it's already embedded.
// Returns an empty base::TimeTicks() if the surface hasn't been embedded yet.
base::TimeTicks GetSurfaceReferencedTimestamp(
const SurfaceId& surface_id) const;
// Returns the primary surface if it exists. Otherwise, this will return the
// most recent surface in |surface_range|. If no surface exists, this will
// return nullptr.
Surface* GetLatestInFlightSurface(const SurfaceRange& surface_range);
// Called by SurfaceAggregator notifying us that it will use |surface| in the
// next display frame. We will notify SurfaceObservers accordingly.
void SurfaceWillBeDrawn(Surface* surface);
// Removes temporary reference to |surface_id| and older surfaces.
void DropTemporaryReference(const SurfaceId& surface_id);
// Returns the corresponding SurfaceAllocationGroup for |surface_id|. A
// SurfaceAllocationGroup will be created for |surface_id| if one doesn't
// exist yet. If there is already a SurfaceAllocationGroup that matches the
// embed token of |surface_id| but its submitter doesn't match |surface_id|'s
// FrameSinkId, nullptr will be returned. In any other case, the returned
// value will always be a valid SurfaceAllocationGroup.
SurfaceAllocationGroup* GetOrCreateAllocationGroupForSurfaceId(
const SurfaceId& surface_id);
// Similar to GetOrCreateAllocationGroupForSurfaceId, but will not attempt to
// create the allocation group if it does not already exist.
SurfaceAllocationGroup* GetAllocationGroupForSurfaceId(
const SurfaceId& surface_id);
// Called by allocation groups when they're ready to destroy and need garbage
// collection.
void SetAllocationGroupsNeedGarbageCollection();
// Returns whether there is any surface blocked on a surface from
// |frame_sink_id|.
bool HasBlockedEmbedder(const FrameSinkId& frame_sink_id) const;
// Indicates that the set of frame sinks being aggregated for display has
// changed since the previous aggregation.
void AggregatedFrameSinksChanged();
using CommitPredicate =
base::FunctionRef<bool(const SurfaceId&, const BeginFrameId&)>;
// Commits all surfaces in range and their referenced surfaces. For each
// surface processed calls `predicate` for each uncommitted frame from oldest
// to newest. If predicate returns true, surface is committed. If not the
// surface processing stops and we go to the next surface.
void CommitFramesInRangeRecursively(const SurfaceRange& range,
const CommitPredicate& predicate);
private:
friend class CompositorFrameSinkSupportTestBase;
friend class FrameSinkManagerTest;
friend class HitTestAggregatorTest;
friend class SurfaceSynchronizationTest;
friend class SurfaceReferencesTest;
friend class SurfaceSynchronizationTest;
using SurfaceIdSet = std::unordered_set<SurfaceId, SurfaceIdHash>;
// The reason for removing a temporary reference.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class RemovedReason {
EMBEDDED = 0, // The surface was embedded.
DROPPED = 1, // The surface won't be embedded so it was dropped.
SKIPPED = 2, // A newer surface was embedded and the surface was skipped.
EXPIRED = 4, // The surface was never embedded and expired.
COPIED = 5, // The surface was copied.
COUNT
};
struct TemporaryReferenceData {
// Used to track old surface references, will be marked as true on first
// timer tick and will be true on second timer tick.
bool marked_as_old = false;
};
// Returns set of surfaces that cannot be garbage-collected.
SurfaceIdSet GetLiveSurfaces();
// Adds a reference from |parent_id| to |child_id| without dealing with
// temporary references.
void AddSurfaceReferenceImpl(const SurfaceReference& reference);
// Removes a reference from a |parent_id| to |child_id|.
void RemoveSurfaceReferenceImpl(const SurfaceReference& reference);
// Returns whether |surface_id| has a temporary reference or not.
bool HasTemporaryReference(const SurfaceId& surface_id) const;
// Adds a temporary reference to |surface_id|. The reference will not have an
// owner initially.
void AddTemporaryReference(const SurfaceId& surface_id);
// Removes temporary reference to |surface_id| and older surfaces. The
// |reason| for removing will be recorded with UMA.
void RemoveTemporaryReferenceImpl(const SurfaceId& surface_id,
RemovedReason reason);
// Marks and then expires old temporary references. This function is run
// periodically by a timer.
void ExpireOldTemporaryReferences();
// Removes the surface from the surface map and destroys it.
void DestroySurfaceInternal(const SurfaceId& surface_id);
#if DCHECK_IS_ON()
// Recursively prints surface references starting at |surface_id| to |str|.
void SurfaceReferencesToStringImpl(const SurfaceId& surface_id,
std::string indent,
std::stringstream* str);
#endif
// Returns true if |surface_id| is in the garbage collector's queue.
bool IsMarkedForDestruction(const SurfaceId& surface_id);
// Garbage-collects the allocation groups if they have signalled that they are
// ready for destruction.
void MaybeGarbageCollectAllocationGroups();
// This returns true if early-acks for frame activation during interaction is
// enabled and if the number of frames since ack and the last interactive
// frame is below the cooldown threshold. This is only true for the Surfaces
// which are not currently being interacted with.
bool ShouldAckNonInteractiveFrame(const CompositorFrameMetadata& ack) const;
// Can be nullptr.
const raw_ptr<SurfaceManagerDelegate> delegate_;
std::optional<uint32_t> activation_deadline_in_frames_;
base::flat_map<base::UnguessableToken,
std::unique_ptr<SurfaceAllocationGroup>>
embed_token_to_allocation_group_;
base::flat_map<
FrameSinkId,
std::vector<raw_ptr<SurfaceAllocationGroup, VectorExperimental>>>
frame_sink_id_to_allocation_groups_;
base::flat_map<SurfaceId, std::unique_ptr<Surface>> surface_map_;
base::ObserverList<SurfaceObserver>::Unchecked observer_list_;
SEQUENCE_CHECKER(sequence_checker_);
base::flat_map<SurfaceId, base::TimeTicks> surfaces_to_destroy_;
// Root SurfaceId that references display root surfaces. There is no Surface
// with this id, it's for bookkeeping purposes only.
const SurfaceId root_surface_id_;
// Always empty set that is returned when there is no entry in |references_|
// for a SurfaceId.
const base::flat_set<SurfaceId> empty_surface_id_set_;
// Used for setting deadlines for surface synchronization.
raw_ptr<const base::TickClock> tick_clock_;
// Keeps track of surface references for a surface. The graph of references is
// stored in parent to child direction. i.e the map stores all direct children
// of the surface specified by |SurfaceId|.
std::unordered_map<SurfaceId, base::flat_set<SurfaceId>, SurfaceIdHash>
references_;
// A map of surfaces that have temporary references.
std::unordered_map<SurfaceId, TemporaryReferenceData, SurfaceIdHash>
temporary_references_;
// A map of pair(the timestamp of the first time a surface gets referenced,
// the number of references that surface has).
std::unordered_map<SurfaceId,
std::pair<base::TimeTicks, uint32_t>,
SurfaceIdHash>
surface_referenced_timestamps_;
// Range tracking information for temporary references. Each map entry is an
// is an ordered list of SurfaceIds that have temporary references with the
// same FrameSinkId. A SurfaceId can be reconstructed with:
// SurfaceId surface_id(key, value[index]);
// The LocalSurfaceIds are stored in the order the surfaces are created in. If
// a reference is added to a later SurfaceId then all temporary references up
// to that point will be removed. This is to handle clients getting out of
// sync, for example the embedded client producing new SurfaceIds faster than
// the embedding client can use them.
std::unordered_map<FrameSinkId, std::vector<LocalSurfaceId>, FrameSinkIdHash>
temporary_reference_ranges_;
std::optional<BeginFrameId> last_interactive_frame_;
// Timer to remove old temporary references that aren't removed after an
// interval of time. The timer will started/stopped so it only runs if there
// are temporary references. Also the timer isn't used with Android WebView.
std::optional<base::RepeatingTimer> expire_timer_;
bool allocation_groups_need_garbage_collection_ = false;
// Maximum length of uncommitted queue, zero means all frames are committed
// automatically.
const size_t max_uncommitted_frames_;
std::optional<uint64_t>
cooldown_frames_for_ack_on_activation_during_interaction_;
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_MANAGER_H_
|