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
ash / frame_sink / frame_sink_holder.h [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_FRAME_SINK_FRAME_SINK_HOLDER_H_
#define ASH_FRAME_SINK_FRAME_SINK_HOLDER_H_
#include <cstdint>
#include <memory>
#include <vector>
#include "ash/ash_export.h"
#include "ash/frame_sink/frame_sink_host.h"
#include "ash/frame_sink/ui_resource_manager.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "ui/aura/window_observer.h"
namespace cc {
class LayerTreeFrameSink;
} // namespace cc
namespace ash {
class FrameSinkHolderTestApi;
// Holds the LayerTreeFrameSink and manages all the interactions with the
// LayerTreeFrameSink. It provides an API to submit compositor frames either
// synchronously or asynchronously. We have this holder class so that, if
// needed, we can make LayerTreeFrameSink outlive the frame_sink_host in order
// to reclaim any exported resources to display compositor. Note: The class is
// intended to be used by the FrameSinkHost class.
class ASH_EXPORT FrameSinkHolder final : public cc::LayerTreeFrameSinkClient,
public viz::BeginFrameObserverBase,
public aura::WindowObserver {
public:
using PresentationCallback =
base::RepeatingCallback<void(const gfx::PresentationFeedback&)>;
// Refer to declaration of `FrameSinkHost::CreateCompositorFrame` for a
// detailed comment.
using GetCompositorFrameCallback =
base::RepeatingCallback<std::unique_ptr<viz::CompositorFrame>(
const viz::BeginFrameAck& begin_frame_ack,
UiResourceManager& resource_manager,
bool auto_update,
const gfx::Size& last_submitted_frame_size,
float last_submitted_frame_dsf)>;
// Refer to declaration of `FrameSinkHost::OnFirstFrameRequested` for a
// detailed comment.
using OnFirstFrameRequestedCallback = base::RepeatingCallback<void()>;
// Refer to declaration of `FrameSinkHost::OnFrameSinkLost` for a detailed
// comment.
using OnFrameSinkLost = base::OnceCallback<void()>;
FrameSinkHolder(
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink,
GetCompositorFrameCallback get_compositor_frame_callback,
OnFirstFrameRequestedCallback on_first_frame_requested_callback,
OnFrameSinkLost on_frame_sink_lost_callback);
FrameSinkHolder(const FrameSinkHolder&) = delete;
FrameSinkHolder& operator=(const FrameSinkHolder&) = delete;
~FrameSinkHolder() override;
// Delete `frame_sink_holder` after having reclaimed all exported resources.
// Returns true if the holder will be deleted immediately.
// TODO(reveman): Find a better way to handle deletion of in-flight resources.
// https://crbug.com/765763
static bool DeleteWhenLastResourceHasBeenReclaimed(
std::unique_ptr<FrameSinkHolder> frame_sink_holder,
aura::Window* host_window);
void set_presentation_callback(PresentationCallback callback) {
presentation_callback_ = std::move(callback);
}
base::WeakPtr<FrameSinkHolder> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
// When auto-update mode is on, we keep on submitting frames asynchronously to
// display compositor without a request to submit a frame via
// `SubmitCompositorFrame()`.
void SetAutoUpdateMode(bool mode);
UiResourceManager& resource_manager() { return resources_manager_; }
// Submits a single compositor frame to display compositor. Auto-submit
// mode must be off to use this method. If synchronous_draw is true, we try to
// submit frame to display compositor right away. Otherwise we will submit the
// frame next time display compositor requests a new frame.
// Note: In certain cases when we cannot submit frames right away, synchronous
// requests will be changed to asynchronous requests.
void SubmitCompositorFrame(bool synchronous_draw);
// 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;
// Overridden from viz::BeginFrameObserverBase:
void OnBeginFrameSourcePausedChanged(bool paused) override;
bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override;
// Overridden from aura::WindowObserver
void OnWindowDestroying(aura::Window* window) override;
private:
friend class FrameSinkHolderTestApi;
void ObserveBeginFrameSource(bool start);
// If we have not consecutively produced a frame in response to OnBeginFrame
// events from the compositor, we can stop observing the
// `begin_frame_source_`. This is because continuous polling from the
// compositor and receiving DidNotProduceFrame responses from the client is
// unnecessary work and can cause power regression.
void MaybeStopObservingBeingFrameSource();
void DidNotProduceFrame(viz::BeginFrameAck&& begin_frame_ack,
cc::FrameSkippedReason reason);
// Create an empty frame that has dsf and size of the last submitted frame.
viz::CompositorFrame CreateEmptyFrame();
void SubmitCompositorFrameInternal(
std::unique_ptr<viz::CompositorFrame> frame);
void ScheduleDelete();
// Returns true if we are waiting to reclaim all the exported resources after
// which we schedule a delete task for the holder.
bool WaitingToScheduleDelete() const;
// Extend the lifetime of `this` by adding it as a observer to `root_window`.
void SetRootWindowForDeletion(aura::Window* root_window);
// True when the display compositor has already asked for a compositor
// frame. This signifies that the gpu process has been fully initialized.
bool first_frame_requested_ = false;
// The layer tree frame sink created from `host_window_.
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink_;
// The currently observed `BeginFrameSource` which will notify us with
// `OnBeginFrameDerivedImpl()`.
raw_ptr<viz::BeginFrameSource> begin_frame_source_ = nullptr;
// True if we submitted a compositor frame and are waiting for a call to
// `DidReceiveCompositorFrameAck()`.
bool pending_compositor_frame_ack_ = false;
// True if we asynchronously need to submit a compositor frame i.e submit a
// frame next time display compositor requests for a new frame via
// `OnBeginFrameDerivedImpl`.
bool pending_compositor_frame_ = false;
// The pixel size and the DSF of the most recently submitted compositor frame.
// If either changes, we'll need to allocate a new local surface ID.
gfx::Size last_frame_size_in_pixels_;
float last_frame_device_scale_factor_ = 1.0f;
// Keeps track of resources that are currently available to be reused in a
// compositor frame and the resources that are in-use by the display
// compositor.
UiResourceManager resources_manager_;
// Generates a frame token for the next compositor frame we create.
viz::FrameTokenGenerator compositor_frame_token_generator_;
// True if `this` is scheduled to be deleted.
bool delete_pending_ = false;
// When true, continuously submit frames asynchronously in the background.
bool auto_update_ = false;
// The callback to notify the client when surface contents have been
// presented.
PresentationCallback presentation_callback_;
// The callback to generate the next compositor frame.
GetCompositorFrameCallback get_compositor_frame_callback_;
// The callback invoked when the display compositor asks for a compositor
// frame for the first time.
OnFirstFrameRequestedCallback on_first_frame_requested_callback_;
// The callback invoked when the connection to `frame_sink_` is lost.
OnFrameSinkLost on_frame_sink_lost_callback_;
bool is_frame_sink_lost_ = false;
// Observation of the root window to which this holder becomes an observer to
// extend its lifespan till all the in-flight resource to display compositor
// are reclaimed.
base::ScopedObservation<aura::Window, aura::WindowObserver>
root_window_observation_{this};
base::ScopedObservation<viz::BeginFrameSource, viz::BeginFrameObserver>
begin_frame_observation_{this};
// The number of DidNotProduceFrame responses since the last time when a frame
// is submitted.
int consecutive_begin_frames_produced_no_frame_count_ = 0;
base::WeakPtrFactory<FrameSinkHolder> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_FRAME_SINK_FRAME_SINK_HOLDER_H_