blob: ba53c4dc6dfc8d96d1480e52b5f26b1a2fe59022 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 <vector>
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.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/surface_dependency_deadline.h"
#include "components/viz/service/viz_service_export.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
class CopyOutputRequest;
}
namespace gfx {
struct PresentationFeedback;
}
namespace ui {
class LatencyInfo;
}
namespace viz {
class SurfaceClient;
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 to two
// CompositorFrames at a given time:
//
// 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.
//
// Pending frame: A pending CompositorFrame cannot be displayed on screen. A
// CompositorFrame is pending if it has unresolved
// dependencies: surface Ids to which there are no active
// CompositorFrames.
//
// This two stage 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.
class VIZ_SERVICE_EXPORT Surface final : public SurfaceDeadlineClient {
public:
using PresentedCallback =
base::OnceCallback<void(const gfx::PresentationFeedback&)>;
Surface(const SurfaceInfo& surface_info,
SurfaceManager* surface_manager,
base::WeakPtr<SurfaceClient> surface_client,
bool needs_sync_tokens,
bool block_activation_on_parent);
~Surface();
void SetDependencyDeadline(
std::unique_ptr<SurfaceDependencyDeadline> deadline);
// Clears the pending and active frame data as well as the
// |seen_first_frame_activation_| bit causing a FirstSurfaceActivation to be
// triggered on the next CompositorFrame activation.
void Reset(base::WeakPtr<SurfaceClient> client);
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();
}
base::WeakPtr<SurfaceClient> client() { return surface_client_; }
bool has_deadline() const { return deadline_ && deadline_->has_deadline(); }
// Inherits the same deadline as the one specified by |surface|. A deadline
// may be set further out in order to avoid doing unnecessary work while a
// parent surface is blocked on dependencies. A deadline may be shortened
// in order to minimize guttering (by unblocking children blocked on their
// grandchildren sooner).
void InheritActivationDeadlineFrom(Surface* surface);
void SetPreviousFrameSurface(Surface* surface);
// Increments the reference count on resources specified by |resources|.
void RefResources(const std::vector<TransferableResource>& resources);
// Decrements the reference count on resources specified by |resources|.
void UnrefResources(const std::vector<ReturnedResource>& resources);
bool needs_sync_tokens() const { return needs_sync_tokens_; }
bool block_activation_on_parent() const {
return block_activation_on_parent_;
}
// Returns false if |frame| is invalid.
// |frame_rejected_callback| will be called once if the frame will not be
// displayed.
// |presented_callback| is called when the |frame| has been turned into light
// the first time on display, or if the |frame| is replaced by another prior
// to display.
bool QueueFrame(CompositorFrame frame,
uint64_t frame_index,
base::ScopedClosureRunner frame_rejected_callback,
PresentedCallback presented_callback);
// Notifies the Surface that a blocking SurfaceId now has an active
// frame.
void NotifySurfaceIdAvailable(const SurfaceId& surface_id);
// Returns whether the Surface is blocked on the provided |surface_id| or a
// predecessor.
bool IsBlockedOn(const SurfaceId& surface_id) const;
// Called if a deadline has been hit and this surface is not yet active but
// it's marked as respecting deadlines.
void ActivatePendingFrameForDeadline(
base::Optional<base::TimeDelta> duration);
using CopyRequestsMap =
std::multimap<RenderPassId, 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 or at
// the client level.
bool HasCopyOutputRequests();
// Returns the most recent frame that is eligible to be rendered.
// You must check whether HasActiveFrame() returns true before calling this
// method.
const CompositorFrame& GetActiveFrame() 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 : 0;
}
void TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
bool TakePresentedCallback(PresentedCallback* callback);
void RunDrawCallback();
void NotifyAggregatedDamage(const gfx::Rect& damage_rect,
base::TimeTicks expected_display_time);
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_;
}
// Returns the set of activation dependencies that have been ignored because
// the last CompositorFrame was activated due to a deadline. Late
// dependencies activate immediately when they arrive.
const base::flat_set<SurfaceId>& late_activation_dependencies() const {
return late_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_processed;
}
// Returns true if at any point, another Surface's CompositorFrame has
// depended on this Surface.
bool HasDependentFrame() const { return seen_first_surface_dependency_; }
// SurfaceDeadlineClient implementation:
void OnDeadline(base::TimeDelta duration) override;
// 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 OnChildActivated(const SurfaceId& surface_id);
// Called when this surface is embedded by another Surface's CompositorFrame.
void OnSurfaceDependencyAdded();
private:
struct SequenceNumbers {
uint32_t parent_sequence_number = 0u;
uint32_t child_sequence_number = 0u;
};
struct FrameData {
FrameData(CompositorFrame&& frame,
uint64_t frame_index,
PresentedCallback presented_callback);
FrameData(FrameData&& other);
~FrameData();
FrameData& operator=(FrameData&& other);
CompositorFrame frame;
uint64_t frame_index;
// Whether the frame has been processed (displayed, or discarded), or not.
bool frame_processed = false;
// TODO(sad): This callback would ideally become part of SurfaceClient API.
PresentedCallback presented_callback;
};
// Rejects CompositorFrames submitted to surfaces referenced from this
// CompositorFrame as fallbacks. This saves some CPU cycles to allow
// children to catch up to the parent.
void RejectCompositorFramesToFallbackSurfaces();
// Updates surface references of the surface using the referenced
// surfaces from the most recent CompositorFrame.
// Modifies surface references stored in SurfaceManager.
void UpdateSurfaceReferences();
// Called to prevent additional CompositorFrames from being accepted into this
// surface. Once a Surface is closed, it cannot accept CompositorFrames again.
void Close();
// Updates the FrameSinkIds observed by this surface to be equal to
// |new_observed_sinks|.
void UpdateObservedSinks(
const base::flat_set<FrameSinkId>& new_observed_sinks);
// 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(base::Optional<base::TimeDelta> duration);
// Called when all of the surface's dependencies have been resolved.
void ActivateFrame(FrameData frame_data,
base::Optional<base::TimeDelta> duration);
// 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 ComputeChangeInDependencies(
const base::flat_map<FrameSinkId, SequenceNumbers>& new_dependencies);
void UnrefFrameResourcesAndRunCallbacks(base::Optional<FrameData> frame_data);
void ClearCopyRequests();
void TakeLatencyInfoFromPendingFrame(
std::vector<ui::LatencyInfo>* latency_info);
static void TakeLatencyInfoFromFrame(
CompositorFrame* frame,
std::vector<ui::LatencyInfo>* latency_info);
void RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> copy_request);
const SurfaceInfo surface_info_;
SurfaceId previous_frame_surface_id_;
SurfaceManager* const surface_manager_;
base::WeakPtr<SurfaceClient> surface_client_;
std::unique_ptr<SurfaceDependencyDeadline> deadline_;
base::Optional<FrameData> pending_frame_data_;
base::Optional<FrameData> active_frame_data_;
bool closed_ = false;
bool seen_first_frame_activation_ = false;
bool seen_first_surface_embedding_ = false;
bool seen_first_surface_dependency_ = false;
const bool needs_sync_tokens_;
const bool block_activation_on_parent_;
base::flat_set<SurfaceId> activation_dependencies_;
base::flat_set<SurfaceId> late_activation_dependencies_;
// A map from FrameSinkIds of SurfaceIds that this surface depends on for
// activation to the latest local_id associated with the given FrameSinkId
// that this surface is dependent on. This map is used to determine which
// FrameSinkIds this surface would like to observe activations for. Once
// the latest activated SurfaceId associated with the given FrameSinkId
// passes the local_id in the map, then this surface is no longer interested
// in observing activations for that FrameSinkId.
base::flat_map<FrameSinkId, SequenceNumbers> frame_sink_id_dependencies_;
// 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_;
// Frame sinks that this surface observe for activation events.
base::flat_set<FrameSinkId> observed_sinks_;
DISALLOW_COPY_AND_ASSIGN(Surface);
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_SURFACES_SURFACE_H_