// Copyright 2016 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_EXO_LAYER_TREE_FRAME_SINK_HOLDER_H_
#define COMPONENTS_EXO_LAYER_TREE_FRAME_SINK_HOLDER_H_
#include <memory>
#include <optional>
#include "base/containers/queue.h"
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "components/exo/frame_sink_resource_manager.h"
#include "components/exo/frame_timing_history.h"
#include "components/exo/wm_helper.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/quads/compositor_frame.h"
namespace viz {
struct FrameTimingDetails;
}
namespace cc::mojo_embedder {
class AsyncLayerTreeFrameSink;
}
namespace exo {
class SurfaceTreeHost;
// When this feature is disabled (by default at the moment), frames are
// submitted to the remote side as soon as they arrive, disregarding BeginFrame
// requests.
//
// TODO(yzshen): Remove this flag and always submit according to BeginFrame
// requests. crbug.com/1408614
BASE_DECLARE_FEATURE(kExoReactiveFrameSubmission);
// This class talks to CompositorFrameSink and keeps track of references to
// the contents of Buffers.
class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient,
public WMHelper::LifetimeManager::Observer,
public viz::BeginFrameObserverBase {
public:
LayerTreeFrameSinkHolder(
SurfaceTreeHost* surface_tree_host,
std::unique_ptr<cc::mojo_embedder::AsyncLayerTreeFrameSink> frame_sink);
LayerTreeFrameSinkHolder(const LayerTreeFrameSinkHolder&) = delete;
LayerTreeFrameSinkHolder& operator=(const LayerTreeFrameSinkHolder&) = delete;
~LayerTreeFrameSinkHolder() override;
// Delete frame sink after having reclaimed and called all resource
// release callbacks.
// TODO(reveman): Find a better way to handle deletion of in-flight resources.
// crbug.com/765763
static void DeleteWhenLastResourceHasBeenReclaimed(
std::unique_ptr<LayerTreeFrameSinkHolder> holder);
// If a frame is submitted "now" (meaning before returning to event loop)
// via SubmitCompositorFrame(), whether it needs full damage.
bool NeedsFullDamageForNextFrame() const { return cached_frame_.has_value(); }
void SubmitCompositorFrame(viz::CompositorFrame frame,
bool submit_now = false);
void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id);
// Properties of the `frame` from the last `SubmitCompositorFrame()` call,
// either from `cached_frame_`, or `frame_sink_`.
float LastDeviceScaleFactor() const;
const gfx::Size& LastSizeInPixels() const;
// Returns true if owned LayerTreeFrameSink has been lost.
bool is_lost() const { return is_lost_; }
FrameSinkResourceManager* resource_manager() { return &resource_manager_; }
// Overridden from cc::LayerTreeFrameSinkClient:
void SetBeginFrameSource(viz::BeginFrameSource* source) override;
std::optional<viz::HitTestRegionList> BuildHitTestData() override;
void ReclaimResources(std::vector<viz::ReturnedResource> resources) override;
void SetTreeActivationCallback(base::RepeatingClosure callback) override {}
void DidReceiveCompositorFrameAck() override;
void DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) override;
void DidLoseLayerTreeFrameSink() override;
void OnDraw(const gfx::Transform& transform,
const gfx::Rect& viewport,
bool resourceless_software_draw,
bool skip_draw) override {}
void SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override {}
void SetExternalTilePriorityConstraints(
const gfx::Rect& viewport_rect,
const gfx::Transform& transform) override {}
void ClearPendingBeginFramesForTesting();
private:
struct PendingBeginFrame {
viz::BeginFrameAck begin_frame_ack;
base::TimeTicks send_deadline_estimate;
};
void ScheduleDelete();
// WMHelper::LifetimeManager::Observer:
void OnDestroyed() override;
// viz::BeginFrameObserverBase:
bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override;
void OnBeginFrameSourcePausedChanged(bool paused) override;
void SubmitCompositorFrameToRemote(viz::CompositorFrame* frame);
// Discards `cached_frame_`, reclaims resources and returns failure
// presentation feedback.
void DiscardCachedFrame(const viz::CompositorFrame* new_frame);
void SendDiscardedFrameNotifications(uint32_t frame_token);
void StopProcessingPendingFrames();
void OnSendDeadlineExpired(bool update_timer);
// Starts timer based on estimated deadline of the first pending BeginFrame
// request; or stops timer if there is no pending BeginFrame request.
void UpdateSubmitFrameTimer();
void ProcessFirstPendingBeginFrame(viz::CompositorFrame* frame);
bool ShouldSubmitFrameNow() const;
void ObserveBeginFrameSource(bool start);
// Returns true if the feature AutoNeedsBeginFrame is enabled, and currently
// we are not receiving BeginFrame requests. In this case, it is allowed to
// submit an unsolicited frame.
bool UnsolicitedFrameAllowed() const;
raw_ptr<SurfaceTreeHost> surface_tree_host_;
std::unique_ptr<cc::mojo_embedder::AsyncLayerTreeFrameSink> frame_sink_;
FrameSinkResourceManager resource_manager_;
std::vector<viz::ResourceId> last_frame_resources_;
std::optional<viz::CompositorFrame> cached_frame_;
// Resources that are submitted and still in use by the remote side.
std::set<viz::ResourceId> in_use_resources_;
bool is_lost_ = false;
bool delete_pending_ = false;
raw_ptr<WMHelper::LifetimeManager> lifetime_manager_ = nullptr;
raw_ptr<viz::BeginFrameSource> begin_frame_source_ = nullptr;
bool observing_begin_frame_source_ = false;
base::queue<PendingBeginFrame> pending_begin_frames_;
// The number of frames submitted to the remote side for which acks haven't
// been received.
int pending_submit_frames_ = 0;
// A queue of discarded frame tokens for which acks and presentation feedbacks
// haven't been sent to `surface_tree_host_`.
base::queue<uint32_t> pending_discarded_frame_notifications_;
base::DeadlineTimer submit_frame_timer_;
const bool reactive_frame_submission_ = false;
// Set if `reactive_frame_submission_` is enabled.
std::optional<FrameTimingHistory> frame_timing_history_;
};
} // namespace exo
#endif // COMPONENTS_EXO_LAYER_TREE_FRAME_SINK_HOLDER_H_