blob: d7630fa8805b931f69d8320826d8981280541e60 [file] [log] [blame]
// 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_H_
#define COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/surfaces/frame_index_constants.h"
#include "components/viz/service/surfaces/pending_copy_output_request.h"
#include "components/viz/service/surfaces/surface_client.h"
#include "components/viz/service/surfaces/surface_dependency_deadline.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
class CopyOutputRequest;
}
namespace gfx {
struct PresentationFeedback;
struct SwapTimings;
}
namespace ui {
class LatencyInfo;
}
namespace viz {
class SurfaceAllocationGroup;
class SurfaceManager;
// A Surface is a representation of a sequence of CompositorFrames with a
// common set of properties uniquely identified by a SurfaceId. In particular,
// all CompositorFrames submitted to a single Surface share properties described
// in SurfaceInfo: device scale factor and size. A Surface can hold up few
// CompositorFrames at a given time:
//
// Uncommitted frames: It's frame that has been received, but hasn't been
// processed yet. There can be up to
// `max_uncommitted_frames_` in this state. If
// `max_uncommitted_frames_` is zero all frames are
// committed as soon as they are received.
//
// Pending frame: A pending CompositorFrame cannot be displayed on
// screen. A CompositorFrame is pending when it has been
// committed but has unresolved dependencies: surface Ids
// to which there are no active CompositorFrames. There
// can be only one pending frame.
//
// Active frame: An active frame is a candidate for display. A
// CompositorFrame is active if it has been explicitly
// marked as active after a deadline has passed or all
// its dependencies are active. There can be only one
// active frame.
//
// This pending+active frame mechanism for managing CompositorFrames from a
// client exists to enable best-effort synchronization across clients. A surface
// subtree will remain pending until all dependencies are resolved: all clients
// have submitted CompositorFrames corresponding to a new property of the
// subtree (e.g. a new size).
//
// Clients are assumed to be untrusted and so a client may not submit a
// CompositorFrame to satisfy the dependency of the parent. Thus, by default, a
// surface has an activation deadline associated with its dependencies. If the
// deadline passes, then the CompositorFrame will activate despite missing
// dependencies. The activated CompositorFrame can specify fallback behavior in
// the event of missing dependencies at display time.
//
// On WebView display compositor runs asynchronously in regards of BeginFrames
// and CompositorFrame submissions, to avoid frame drops due to racyness
// uncommitted queue mechanism is used. When clients submits frame it goes to
// the queue and when the display compositor draws frames are committed from
// the queue to the pending or active frame.
class VIZ_SERVICE_EXPORT Surface final {
public:
class PresentationHelper {
public:
PresentationHelper(base::WeakPtr<SurfaceClient> surface_client,
uint32_t frame_token);
PresentationHelper(const PresentationHelper&) = delete;
PresentationHelper& operator=(const PresentationHelper&) = delete;
~PresentationHelper();
void DidPresent(base::TimeTicks draw_start_timestamp,
const gfx::SwapTimings& timings,
const gfx::PresentationFeedback& feedback);
private:
base::WeakPtr<SurfaceClient> surface_client_;
const uint32_t frame_token_;
};
using PresentedCallback =
base::OnceCallback<void(const gfx::PresentationFeedback&)>;
enum QueueFrameResult { REJECTED, ACCEPTED_ACTIVE, ACCEPTED_PENDING };
using CommitPredicate =
base::RepeatingCallback<bool(const SurfaceId&, const BeginFrameId&)>;
Surface(const SurfaceInfo& surface_info,
SurfaceManager* surface_manager,
SurfaceAllocationGroup* allocation_group,
base::WeakPtr<SurfaceClient> surface_client,
size_t max_uncommitted_frames);
Surface(const Surface&) = delete;
Surface& operator=(const Surface&) = delete;
~Surface();
void SetDependencyDeadline(
std::unique_ptr<SurfaceDependencyDeadline> deadline);
const SurfaceId& surface_id() const { return surface_info_.id(); }
const SurfaceId& previous_frame_surface_id() const {
return previous_frame_surface_id_;
}
const gfx::Size& size_in_pixels() const {
return surface_info_.size_in_pixels();
}
float device_scale_factor() const {
return surface_info_.device_scale_factor();
}
base::WeakPtr<SurfaceClient> client() { return surface_client_; }
bool has_deadline() const { return deadline_ && deadline_->has_deadline(); }
absl::optional<base::TimeTicks> deadline_for_testing() const {
return deadline_->deadline_for_testing();
}
void SetPreviousFrameSurface(Surface* surface);
// Returns false if |frame| is invalid. |frame_rejected_callback| will be
// called once if the frame will not be displayed.
QueueFrameResult QueueFrame(
CompositorFrame frame,
uint64_t frame_index,
base::ScopedClosureRunner frame_rejected_callback);
// Commits frame(s) in this Surface and its dependencies. For each affected
// surface, the predicate will be called for each uncommitted frame in each
// surface from the oldest to the newest and will abort at first case of
// returning false.
void CommitFramesRecursively(const CommitPredicate& predicate);
// Notifies the Surface that a blocking SurfaceId now has an active
// frame.
void NotifySurfaceIdAvailable(const SurfaceId& surface_id);
// Called if a deadline has been hit and this surface is not yet active but
// it's marked as respecting deadlines.
void ActivatePendingFrameForDeadline();
using CopyRequestsMap =
std::multimap<CompositorRenderPassId, std::unique_ptr<CopyOutputRequest>>;
// Adds each CopyOutputRequest in the current frame to copy_requests. The
// caller takes ownership of them. |copy_requests| is keyed by RenderPass
// ids.
void TakeCopyOutputRequests(CopyRequestsMap* copy_requests);
// Takes CopyOutputRequests made at the client level and adds them to this
// Surface.
void TakeCopyOutputRequestsFromClient();
// Returns whether there is a CopyOutputRequest inside the active frame.
bool HasCopyOutputRequests() const;
// Returns the most recent frame or frame metadata that is eligible to be
// rendered. You must check whether HasActiveFrame() returns true before
// calling these methods.
// Note that we prefer to call GetActiveFrameMetadata if the only thing that
// is required from the frame is the metadata.
const CompositorFrame& GetActiveFrame() const;
const CompositorFrameMetadata& GetActiveFrameMetadata() const;
void SetInterpolatedFrame(CompositorFrame frame);
const CompositorFrame& GetActiveOrInterpolatedFrame() const;
bool HasInterpolatedFrame() const;
// Returns true if the active or interpolated frame has damage due to a
// surface animation. This means that the damage should be respected even if
// the active frame index has not changed.
bool HasSurfaceAnimationDamage() const;
// Returns the currently pending frame. You must check where HasPendingFrame()
// returns true before calling this method.
const CompositorFrame& GetPendingFrame();
// Returns a number that increments by 1 every time a new frame is enqueued.
uint64_t GetActiveFrameIndex() const {
return active_frame_data_ ? active_frame_data_->frame_index
: kInvalidFrameIndex;
}
void TakeActiveLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
void TakeActiveAndPendingLatencyInfo(
std::vector<ui::LatencyInfo>* latency_info);
// Callers of this function must call |DidPresent| on the returned
// PresentationHelper, at the appropriate point in the future.
std::unique_ptr<Surface::PresentationHelper>
TakePresentationHelperForPresentNotification();
void SendAckToClient();
void MarkAsDrawn();
void NotifyAggregatedDamage(const gfx::Rect& damage_rect,
base::TimeTicks expected_display_time);
// True if video capture has been started. False if it has been stopped.
// This information is used by direct composition overlays to decide whether
// overlay should be used. Not all frames have copy requests after video
// capture. We don't want to constantly switch between overlay and non-overlay
// during video playback.
bool IsVideoCaptureOnFromClient();
base::flat_set<base::PlatformThreadId> GetThreadIds();
const base::flat_set<SurfaceId>& active_referenced_surfaces() const {
return active_referenced_surfaces_;
}
// Returns the set of dependencies blocking this surface's pending frame
// that themselves have not yet activated.
const base::flat_set<SurfaceId>& activation_dependencies() const {
return activation_dependencies_;
}
bool HasActiveFrame() const { return active_frame_data_.has_value(); }
bool HasPendingFrame() const { return pending_frame_data_.has_value(); }
bool HasUndrawnActiveFrame() const {
return HasActiveFrame() && !active_frame_data_->frame_drawn;
}
bool HasUnackedActiveFrame() const {
return HasActiveFrame() && !active_frame_data_->frame_acked;
}
bool seen_first_surface_embedding() const {
return seen_first_surface_embedding_;
}
SurfaceAllocationGroup* allocation_group() const { return allocation_group_; }
// Called when this surface will be included in the next display frame.
void OnWillBeDrawn();
// Called when |surface_id| is activated for the first time and its part of a
// referenced SurfaceRange.
void OnChildActivatedForActiveFrame(const SurfaceId& surface_id);
// Called when the embedder of this surface has been activated and therefore
// this surface should activate too by deadline inheritance.
void ActivatePendingFrameForInheritedDeadline();
// Returns whether the LatencyInfo of the current pending and active frames
// is already taken.
bool is_latency_info_taken() { return is_latency_info_taken_; }
// Called by a blocking SurfaceAllocationGroup when |activation_dependency|
// is resolved. |this| will be automatically unregistered from |group|, the
// SurfaceAllocationGroup corresponding to |activation_dependency|.
void OnActivationDependencyResolved(const SurfaceId& activation_dependency,
SurfaceAllocationGroup* group);
// Notifies that this surface is no longer the primary surface of the
// embedder. All future CompositorFrames will activate as soon as they arrive
// and if a pending frame currently exists it will immediately activate as
// well. This allows the client to not wait for acks from the fallback
// surfaces and be able to submit to the primary surface.
void SetIsFallbackAndMaybeActivate();
void ActivateIfDeadlinePassed();
std::unique_ptr<gfx::DelegatedInkMetadata> TakeDelegatedInkMetadata();
base::WeakPtr<Surface> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
// Always placed the given |copy_request| on the root render pass.
void RequestCopyOfOutputOnRootRenderPass(
std::unique_ptr<CopyOutputRequest> copy_request);
// Places the copy-of-output request on the render pass defined by the given
// id. Returns true if the request has been successfully queued and false
// otherwise.
bool RequestCopyOfOutputOnActiveFrameRenderPassId(
std::unique_ptr<CopyOutputRequest> copy_request,
CompositorRenderPassId render_pass_id);
// Returns frame id of the oldest uncommitted frame if any,
absl::optional<BeginFrameId> GetFirstUncommitedFrameId();
// Returns frame id of the oldest uncommitted frame that is newer than
// provided `frame_id`.
absl::optional<BeginFrameId> GetUncommitedFrameIdNewerThan(
const BeginFrameId& frame_id);
private:
struct FrameData {
FrameData(CompositorFrame&& frame, uint64_t frame_index);
FrameData(FrameData&& other);
~FrameData();
FrameData& operator=(FrameData&& other);
// Delegated ink metadata should only be used for a single frame, so it
// should be taken from the FrameData to use.
std::unique_ptr<gfx::DelegatedInkMetadata> TakeDelegatedInkMetadata() {
return std::move(frame.metadata.delegated_ink_metadata);
}
void SendAckIfNeeded(SurfaceClient* client);
CompositorFrame frame;
uint64_t frame_index;
// Whether the frame has been displayed or not.
bool frame_drawn = false;
bool frame_acked = false;
// Whether there is a pending presentation callback (via DidPresentSurface).
// This typically happens when a frame is swapped - the Display will ask
// for a callback that will supply presentation feedback to the client.
bool will_be_notified_of_presentation = false;
};
// Places the copy-of-output request on the render pass defined by
// |PendingCopyOutputRequest::subtree_capture_id| if such a render pass
// exists, otherwise the request will be ignored.
void RequestCopyOfOutput(
PendingCopyOutputRequest pending_copy_output_request);
// Updates surface references of the surface using the referenced
// surfaces from the most recent CompositorFrame.
// Modifies surface references stored in SurfaceManager.
void UpdateSurfaceReferences();
// Updates the set of allocation groups referenced by the active frame. Calls
// RegisterEmbedder and UnregisterEmbedder on the allocation groups as
// appropriate.
void UpdateReferencedAllocationGroups(
std::vector<SurfaceAllocationGroup*> new_referenced_allocation_groups);
// Recomputes active references for this surface when it activates. This
// method will also update the observed sinks based on the referenced ranges
// in the submitted compositor frame.
void RecomputeActiveReferencedSurfaces();
void ActivatePendingFrame();
// Called when all of the surface's dependencies have been resolved.
void ActivateFrame(FrameData frame_data);
// Called when display compositor is ready for this frame to be processed and
// it can become pending or active.
QueueFrameResult CommitFrame(FrameData frame);
// Resolve the activation deadline specified by |current_frame| into a wall
// time to be used by SurfaceDependencyDeadline.
FrameDeadline ResolveFrameDeadline(const CompositorFrame& current_frame);
// Updates the set of unresolved activation dependenices of the
// |current_frame|. If the deadline requested by the frame is 0 then no
// dependencies will be added even if they're not yet available.
void UpdateActivationDependencies(const CompositorFrame& current_frame);
void UnrefFrameResourcesAndRunCallbacks(absl::optional<FrameData> frame_data);
void ClearCopyRequests();
void TakePendingLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
static void TakeLatencyInfoFromFrame(
CompositorFrame* frame,
std::vector<ui::LatencyInfo>* latency_info);
const SurfaceInfo surface_info_;
SurfaceId previous_frame_surface_id_;
const raw_ptr<SurfaceManager> surface_manager_;
base::WeakPtr<SurfaceClient> surface_client_;
std::unique_ptr<SurfaceDependencyDeadline> deadline_;
absl::optional<FrameData> pending_frame_data_;
absl::optional<FrameData> active_frame_data_;
// Queue of uncommitted frames, oldest first.
base::circular_deque<FrameData> uncommitted_frames_;
absl::optional<CompositorFrame> interpolated_frame_;
bool seen_first_frame_activation_ = false;
bool seen_first_surface_embedding_ = false;
// A set of all valid SurfaceIds contained |last_surface_id_for_range_| to
// avoid recompution.
base::flat_set<SurfaceId> active_referenced_surfaces_;
// Keeps track of the referenced surface for each SurfaceRange. i.e the i-th
// element is the referenced SurfaceId in the i-th SurfaceRange. If a
// SurfaceRange doesn't contain any active surfaces then the corresponding
// entry in this vector is an unvalid SurfaceId.
std::vector<SurfaceId> last_surface_id_for_range_;
// Allocation groups that this surface references by its active frame.
base::flat_set<SurfaceAllocationGroup*> referenced_allocation_groups_;
// The set of the SurfaceIds that are blocking the pending frame from being
// activated.
base::flat_set<SurfaceId> activation_dependencies_;
// The SurfaceAllocationGroups corresponding to the surfaces in
// |activation_dependencies_|. When an activation dependency is
// resolved, the corresponding SurfaceAllocationGroup will call back into this
// surface to let us know.
base::flat_set<SurfaceAllocationGroup*> blocking_allocation_groups_;
bool is_fallback_ = false;
bool is_latency_info_taken_ = false;
const raw_ptr<SurfaceAllocationGroup> allocation_group_;
const size_t max_uncommitted_frames_;
base::WeakPtrFactory<Surface> weak_factory_{this};
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_H_