OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "blimp/client/core/compositor/blimp_compositor.h" | |
6 | |
7 #include "base/bind_helpers.h" | |
8 #include "base/command_line.h" | |
9 #include "base/memory/ptr_util.h" | |
10 #include "base/metrics/histogram_macros.h" | |
11 #include "base/numerics/safe_conversions.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/threading/thread.h" | |
14 #include "base/threading/thread_local.h" | |
15 #include "base/threading/thread_restrictions.h" | |
16 #include "base/threading/thread_task_runner_handle.h" | |
17 #include "blimp/client/core/compositor/blimp_compositor_dependencies.h" | |
18 #include "blimp/client/core/compositor/blimp_compositor_frame_sink.h" | |
19 #include "blimp/client/public/compositor/compositor_dependencies.h" | |
20 #include "blimp/net/blimp_stats.h" | |
21 #include "cc/animation/animation_host.h" | |
22 #include "cc/blimp/client_picture_cache.h" | |
23 #include "cc/blimp/compositor_state_deserializer.h" | |
24 #include "cc/blimp/image_serialization_processor.h" | |
25 #include "cc/layers/layer.h" | |
26 #include "cc/layers/surface_layer.h" | |
27 #include "cc/output/compositor_frame_sink.h" | |
28 #include "cc/proto/compositor_message.pb.h" | |
29 #include "cc/surfaces/surface.h" | |
30 #include "cc/surfaces/surface_factory.h" | |
31 #include "cc/surfaces/surface_id_allocator.h" | |
32 #include "cc/surfaces/surface_manager.h" | |
33 #include "cc/trees/layer_tree_host_in_process.h" | |
34 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" | |
35 #include "net/base/net_errors.h" | |
36 #include "ui/gl/gl_surface.h" | |
37 | |
38 namespace blimp { | |
39 namespace client { | |
40 | |
41 class BlimpCompositor::FrameTrackingSwapPromise : public cc::SwapPromise { | |
42 public: | |
43 FrameTrackingSwapPromise( | |
44 std::unique_ptr<cc::CopyOutputRequest> copy_request, | |
45 base::WeakPtr<BlimpCompositor> compositor, | |
46 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) | |
47 : copy_request_(std::move(copy_request)), | |
48 compositor_weak_ptr_(compositor), | |
49 main_task_runner_(std::move(main_task_runner)) {} | |
50 ~FrameTrackingSwapPromise() override = default; | |
51 | |
52 // cc::SwapPromise implementation. | |
53 void DidActivate() override {} | |
54 void WillSwap(cc::CompositorFrameMetadata* metadata) override {} | |
55 void DidSwap() override { | |
56 // DidSwap could be called on compositor thread and we need this to run on | |
57 // the main thread. | |
58 main_task_runner_->PostTask( | |
59 FROM_HERE, | |
60 base::Bind(&BlimpCompositor::MakeCopyRequestOnNextSwap, | |
61 compositor_weak_ptr_, base::Passed(©_request_))); | |
62 } | |
63 DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { | |
64 switch (reason) { | |
65 case DidNotSwapReason::SWAP_FAILS: | |
66 // The swap will fail if there is no frame damage, we can queue the | |
67 // request right away. | |
68 main_task_runner_->PostTask( | |
69 FROM_HERE, base::Bind(&BlimpCompositor::RequestCopyOfOutput, | |
70 compositor_weak_ptr_, | |
71 base::Passed(©_request_), false)); | |
72 break; | |
73 case DidNotSwapReason::COMMIT_FAILS: | |
74 // The commit fails when the host is going away. | |
75 break; | |
76 case DidNotSwapReason::COMMIT_NO_UPDATE: | |
77 main_task_runner_->PostTask( | |
78 FROM_HERE, base::Bind(&BlimpCompositor::RequestCopyOfOutput, | |
79 compositor_weak_ptr_, | |
80 base::Passed(©_request_), false)); | |
81 break; | |
82 case DidNotSwapReason::ACTIVATION_FAILS: | |
83 // Failure to activate the pending tree implies either the host in going | |
84 // away or the FrameSink was lost. | |
85 break; | |
86 } | |
87 return DidNotSwapAction::BREAK_PROMISE; | |
88 } | |
89 int64_t TraceId() const override { return 0; } | |
90 | |
91 private: | |
92 std::unique_ptr<cc::CopyOutputRequest> copy_request_; | |
93 base::WeakPtr<BlimpCompositor> compositor_weak_ptr_; | |
94 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | |
95 }; | |
96 | |
97 // static | |
98 std::unique_ptr<BlimpCompositor> BlimpCompositor::Create( | |
99 BlimpCompositorDependencies* compositor_dependencies, | |
100 BlimpCompositorClient* client) { | |
101 std::unique_ptr<BlimpCompositor> compositor = | |
102 base::WrapUnique(new BlimpCompositor(compositor_dependencies, client)); | |
103 compositor->Initialize(); | |
104 return compositor; | |
105 } | |
106 | |
107 BlimpCompositor::BlimpCompositor( | |
108 BlimpCompositorDependencies* compositor_dependencies, | |
109 BlimpCompositorClient* client) | |
110 : client_(client), | |
111 compositor_dependencies_(compositor_dependencies), | |
112 frame_sink_id_(compositor_dependencies_->GetEmbedderDependencies() | |
113 ->AllocateFrameSinkId()), | |
114 proxy_client_(nullptr), | |
115 bound_to_proxy_(false), | |
116 compositor_frame_sink_request_pending_(false), | |
117 layer_(cc::Layer::Create()), | |
118 weak_ptr_factory_(this) { | |
119 DCHECK(thread_checker_.CalledOnValidThread()); | |
120 } | |
121 | |
122 void BlimpCompositor::Initialize() { | |
123 surface_id_allocator_ = base::MakeUnique<cc::SurfaceIdAllocator>(); | |
124 GetEmbedderDeps()->GetSurfaceManager()->RegisterFrameSinkId(frame_sink_id_); | |
125 surface_factory_ = base::MakeUnique<cc::SurfaceFactory>( | |
126 frame_sink_id_, GetEmbedderDeps()->GetSurfaceManager(), this); | |
127 animation_host_ = cc::AnimationHost::CreateMainInstance(); | |
128 host_ = CreateLayerTreeHost(); | |
129 | |
130 std::unique_ptr<cc::ClientPictureCache> client_picture_cache = | |
131 compositor_dependencies_->GetImageSerializationProcessor() | |
132 ->CreateClientPictureCache(); | |
133 compositor_state_deserializer_ = | |
134 base::MakeUnique<cc::CompositorStateDeserializer>( | |
135 host_.get(), std::move(client_picture_cache), this); | |
136 } | |
137 | |
138 BlimpCompositor::~BlimpCompositor() { | |
139 DCHECK(thread_checker_.CalledOnValidThread()); | |
140 | |
141 DestroyLayerTreeHost(); | |
142 GetEmbedderDeps()->GetSurfaceManager()->InvalidateFrameSinkId(frame_sink_id_); | |
143 } | |
144 | |
145 void BlimpCompositor::SetVisible(bool visible) { | |
146 host_->SetVisible(visible); | |
147 } | |
148 | |
149 bool BlimpCompositor::IsVisible() const { | |
150 return host_->IsVisible(); | |
151 } | |
152 | |
153 bool BlimpCompositor::HasPendingFrameUpdateFromEngine() const { | |
154 return pending_frame_update_.get() != nullptr; | |
155 } | |
156 | |
157 void BlimpCompositor::RequestCopyOfOutput( | |
158 std::unique_ptr<cc::CopyOutputRequest> copy_request, | |
159 bool flush_pending_update) { | |
160 // If we don't have a FrameSink, fail right away. | |
161 if (!bound_to_proxy_) | |
162 return; | |
163 | |
164 if (flush_pending_update) { | |
165 // Always request a commit when queuing the promise to make sure that any | |
166 // frames pending draws are cleared from the pipeline. | |
167 host_->QueueSwapPromise(base::MakeUnique<FrameTrackingSwapPromise>( | |
168 std::move(copy_request), weak_ptr_factory_.GetWeakPtr(), | |
169 base::ThreadTaskRunnerHandle::Get())); | |
170 host_->SetNeedsCommit(); | |
171 } else if (local_frame_id_.is_valid()) { | |
172 // Make a copy request for the surface directly. | |
173 surface_factory_->RequestCopyOfSurface(std::move(copy_request)); | |
174 } | |
175 } | |
176 | |
177 void BlimpCompositor::UpdateLayerTreeHost() { | |
178 // UpdateLayerTreeHost marks the end of reporting of any deltas from the impl | |
179 // thread. So send a client state update if the local state was modified now. | |
180 FlushClientState(); | |
181 | |
182 if (pending_frame_update_) { | |
183 compositor_state_deserializer_->DeserializeCompositorUpdate( | |
184 pending_frame_update_->layer_tree_host()); | |
185 pending_frame_update_ = nullptr; | |
186 cc::proto::CompositorMessage frame_ack; | |
187 frame_ack.set_frame_ack(true); | |
188 client_->SendCompositorMessage(frame_ack); | |
189 } | |
190 | |
191 // Send back any deltas that have not yet been resolved on the main thread | |
192 // back to the impl thread. | |
193 compositor_state_deserializer_->SendUnappliedDeltasToLayerTreeHost(); | |
194 } | |
195 | |
196 void BlimpCompositor::ApplyViewportDeltas( | |
197 const gfx::Vector2dF& inner_delta, | |
198 const gfx::Vector2dF& outer_delta, | |
199 const gfx::Vector2dF& elastic_overscroll_delta, | |
200 float page_scale, | |
201 float top_controls_delta) { | |
202 compositor_state_deserializer_->ApplyViewportDeltas( | |
203 inner_delta, outer_delta, elastic_overscroll_delta, page_scale, | |
204 top_controls_delta); | |
205 } | |
206 | |
207 void BlimpCompositor::RequestNewCompositorFrameSink() { | |
208 DCHECK(!bound_to_proxy_); | |
209 DCHECK(!compositor_frame_sink_request_pending_); | |
210 | |
211 compositor_frame_sink_request_pending_ = true; | |
212 GetEmbedderDeps()->GetContextProviders( | |
213 base::Bind(&BlimpCompositor::OnContextProvidersCreated, | |
214 weak_ptr_factory_.GetWeakPtr())); | |
215 } | |
216 | |
217 void BlimpCompositor::DidInitializeCompositorFrameSink() { | |
218 compositor_frame_sink_request_pending_ = false; | |
219 } | |
220 | |
221 void BlimpCompositor::DidCommitAndDrawFrame() {} | |
222 | |
223 void BlimpCompositor::OnCompositorMessageReceived( | |
224 std::unique_ptr<cc::proto::CompositorMessage> message) { | |
225 cc::proto::CompositorMessage* message_received = message.get(); | |
226 | |
227 if (message_received->has_layer_tree_host()) { | |
228 DCHECK(!pending_frame_update_) | |
229 << "We should have only a single frame in flight"; | |
230 | |
231 UMA_HISTOGRAM_MEMORY_KB("Blimp.Compositor.CommitSizeKb", | |
232 (float)message->ByteSize() / 1024); | |
233 BlimpStats::GetInstance()->Add(BlimpStats::COMMIT, 1); | |
234 | |
235 pending_frame_update_ = std::move(message); | |
236 host_->SetNeedsAnimate(); | |
237 } | |
238 | |
239 if (message_received->client_state_update_ack()) { | |
240 DCHECK(client_state_update_ack_pending_); | |
241 | |
242 client_state_update_ack_pending_ = false; | |
243 compositor_state_deserializer_->DidApplyStateUpdatesOnEngine(); | |
244 | |
245 // If there are any updates that we have queued because we were waiting for | |
246 // an ack, send them now. | |
247 FlushClientState(); | |
248 } | |
249 } | |
250 | |
251 const base::WeakPtr<cc::InputHandler>& BlimpCompositor::GetInputHandler() { | |
252 return host_->GetInputHandler(); | |
253 } | |
254 | |
255 void BlimpCompositor::OnContextProvidersCreated( | |
256 const scoped_refptr<cc::ContextProvider>& compositor_context_provider, | |
257 const scoped_refptr<cc::ContextProvider>& worker_context_provider) { | |
258 DCHECK(!bound_to_proxy_) << "Any connection to the old CompositorFrameSink " | |
259 "should have been destroyed"; | |
260 | |
261 // Make sure we still have a host and we're still expecting a | |
262 // CompositorFrameSink. This can happen if the host dies while the request is | |
263 // outstanding and we build a new one that hasn't asked for a surface yet. | |
264 if (!compositor_frame_sink_request_pending_) | |
265 return; | |
266 | |
267 // Try again if the context creation failed. | |
268 if (!compositor_context_provider) { | |
269 GetEmbedderDeps()->GetContextProviders( | |
270 base::Bind(&BlimpCompositor::OnContextProvidersCreated, | |
271 weak_ptr_factory_.GetWeakPtr())); | |
272 return; | |
273 } | |
274 | |
275 auto compositor_frame_sink = base::MakeUnique<BlimpCompositorFrameSink>( | |
276 std::move(compositor_context_provider), | |
277 std::move(worker_context_provider), | |
278 GetEmbedderDeps()->GetGpuMemoryBufferManager(), nullptr, | |
279 base::ThreadTaskRunnerHandle::Get(), weak_ptr_factory_.GetWeakPtr()); | |
280 | |
281 host_->SetCompositorFrameSink(std::move(compositor_frame_sink)); | |
282 } | |
283 | |
284 void BlimpCompositor::BindToProxyClient( | |
285 base::WeakPtr<BlimpCompositorFrameSinkProxyClient> proxy_client) { | |
286 DCHECK(thread_checker_.CalledOnValidThread()); | |
287 DCHECK(!bound_to_proxy_); | |
288 | |
289 bound_to_proxy_ = true; | |
290 proxy_client_ = proxy_client; | |
291 } | |
292 | |
293 void BlimpCompositor::SubmitCompositorFrame(cc::CompositorFrame frame) { | |
294 DCHECK(thread_checker_.CalledOnValidThread()); | |
295 DCHECK(bound_to_proxy_); | |
296 | |
297 cc::RenderPass* root_pass = frame.render_pass_list.back().get(); | |
298 gfx::Size surface_size = root_pass->output_rect.size(); | |
299 | |
300 if (!local_frame_id_.is_valid() || current_surface_size_ != surface_size) { | |
301 DestroyDelegatedContent(); | |
302 DCHECK(layer_->children().empty()); | |
303 | |
304 local_frame_id_ = surface_id_allocator_->GenerateId(); | |
305 current_surface_size_ = surface_size; | |
306 | |
307 // manager must outlive compositors using it. | |
308 cc::SurfaceManager* surface_manager = | |
309 GetEmbedderDeps()->GetSurfaceManager(); | |
310 auto content_layer = | |
311 cc::SurfaceLayer::Create(surface_manager->reference_factory()); | |
312 cc::SurfaceId surface_id(surface_factory_->frame_sink_id(), | |
313 local_frame_id_); | |
314 content_layer->SetSurfaceInfo( | |
315 cc::SurfaceInfo(surface_id, 1.f, surface_size)); | |
316 content_layer->SetBounds(current_surface_size_); | |
317 content_layer->SetIsDrawable(true); | |
318 content_layer->SetContentsOpaque(true); | |
319 | |
320 layer_->AddChild(content_layer); | |
321 } | |
322 | |
323 surface_factory_->SubmitCompositorFrame( | |
324 local_frame_id_, std::move(frame), | |
325 base::Bind(&BlimpCompositor::SubmitCompositorFrameAck, | |
326 weak_ptr_factory_.GetWeakPtr())); | |
327 | |
328 for (auto& copy_request : copy_requests_for_next_swap_) { | |
329 surface_factory_->RequestCopyOfSurface(std::move(copy_request)); | |
330 } | |
331 copy_requests_for_next_swap_.clear(); | |
332 } | |
333 | |
334 void BlimpCompositor::SubmitCompositorFrameAck() { | |
335 compositor_dependencies_->GetCompositorTaskRunner()->PostTask( | |
336 FROM_HERE, | |
337 base::Bind(&BlimpCompositorFrameSinkProxyClient::SubmitCompositorFrameAck, | |
338 proxy_client_)); | |
339 } | |
340 | |
341 void BlimpCompositor::MakeCopyRequestOnNextSwap( | |
342 std::unique_ptr<cc::CopyOutputRequest> copy_request) { | |
343 copy_requests_for_next_swap_.push_back(std::move(copy_request)); | |
344 } | |
345 | |
346 void BlimpCompositor::UnbindProxyClient() { | |
347 DCHECK(thread_checker_.CalledOnValidThread()); | |
348 DCHECK(bound_to_proxy_); | |
349 | |
350 DestroyDelegatedContent(); | |
351 surface_factory_->Reset(); | |
352 bound_to_proxy_ = false; | |
353 proxy_client_ = nullptr; | |
354 } | |
355 | |
356 void BlimpCompositor::ReturnResources( | |
357 const cc::ReturnedResourceArray& resources) { | |
358 DCHECK(bound_to_proxy_); | |
359 compositor_dependencies_->GetCompositorTaskRunner()->PostTask( | |
360 FROM_HERE, | |
361 base::Bind( | |
362 &BlimpCompositorFrameSinkProxyClient::ReclaimCompositorResources, | |
363 proxy_client_, resources)); | |
364 } | |
365 | |
366 void BlimpCompositor::DidUpdateLocalState() { | |
367 client_state_dirty_ = true; | |
368 } | |
369 | |
370 void BlimpCompositor::FlushClientState() { | |
371 // If the client state has not been modified, we don't need to send an update. | |
372 if (!client_state_dirty_) | |
373 return; | |
374 | |
375 // If we had sent an update and an ack for it is still pending, we can't send | |
376 // another update till the ack is received. | |
377 if (client_state_update_ack_pending_) | |
378 return; | |
379 | |
380 cc::proto::CompositorMessage message; | |
381 message.set_frame_ack(false); | |
382 compositor_state_deserializer_->PullClientStateUpdate( | |
383 message.mutable_client_state_update()); | |
384 | |
385 client_state_dirty_ = false; | |
386 client_state_update_ack_pending_ = true; | |
387 client_->SendCompositorMessage(message); | |
388 } | |
389 | |
390 CompositorDependencies* BlimpCompositor::GetEmbedderDeps() { | |
391 return compositor_dependencies_->GetEmbedderDependencies(); | |
392 } | |
393 | |
394 void BlimpCompositor::DestroyDelegatedContent() { | |
395 if (!local_frame_id_.is_valid()) | |
396 return; | |
397 | |
398 // Remove any references for the surface layer that uses this | |
399 // |local_frame_id_|. | |
400 layer_->RemoveAllChildren(); | |
401 surface_factory_->EvictSurface(); | |
402 local_frame_id_ = cc::LocalFrameId(); | |
403 } | |
404 | |
405 std::unique_ptr<cc::LayerTreeHostInProcess> | |
406 BlimpCompositor::CreateLayerTreeHost() { | |
407 DCHECK(animation_host_); | |
408 std::unique_ptr<cc::LayerTreeHostInProcess> host; | |
409 | |
410 cc::LayerTreeHostInProcess::InitParams params; | |
411 params.client = this; | |
412 params.task_graph_runner = compositor_dependencies_->GetTaskGraphRunner(); | |
413 params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); | |
414 params.image_serialization_processor = | |
415 compositor_dependencies_->GetImageSerializationProcessor(); | |
416 | |
417 cc::LayerTreeSettings* settings = | |
418 compositor_dependencies_->GetLayerTreeSettings(); | |
419 params.settings = settings; | |
420 params.mutator_host = animation_host_.get(); | |
421 | |
422 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner = | |
423 compositor_dependencies_->GetCompositorTaskRunner(); | |
424 | |
425 host = cc::LayerTreeHostInProcess::CreateThreaded(compositor_task_runner, | |
426 ¶ms); | |
427 | |
428 return host; | |
429 } | |
430 | |
431 void BlimpCompositor::DestroyLayerTreeHost() { | |
432 DCHECK(host_); | |
433 | |
434 // Tear down the output surface connection with the old LayerTreeHost | |
435 // instance. | |
436 DestroyDelegatedContent(); | |
437 | |
438 // Destroy the old LayerTreeHost state. | |
439 host_.reset(); | |
440 | |
441 // Cancel any outstanding CompositorFrameSink requests. That way if we get an | |
442 // async callback related to the old request we know to drop it. | |
443 compositor_frame_sink_request_pending_ = false; | |
444 } | |
445 | |
446 } // namespace client | |
447 } // namespace blimp | |
OLD | NEW |