OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "cc/blimp/layer_tree_host_remote.h" | |
6 | |
7 #include "base/atomic_sequence_num.h" | |
8 #include "base/auto_reset.h" | |
9 #include "base/memory/ptr_util.h" | |
10 #include "cc/blimp/compositor_proto_state.h" | |
11 #include "cc/blimp/engine_picture_cache.h" | |
12 #include "cc/blimp/picture_data_conversions.h" | |
13 #include "cc/blimp/remote_compositor_bridge.h" | |
14 #include "cc/output/compositor_frame_sink.h" | |
15 #include "cc/proto/compositor_message.pb.h" | |
16 #include "cc/proto/gfx_conversions.h" | |
17 #include "cc/proto/layer_tree_host.pb.h" | |
18 #include "cc/trees/layer_tree.h" | |
19 #include "cc/trees/layer_tree_host_client.h" | |
20 #include "cc/trees/layer_tree_host_common.h" | |
21 #include "cc/trees/mutator_host.h" | |
22 #include "cc/trees/task_runner_provider.h" | |
23 #include "ui/gfx/geometry/scroll_offset.h" | |
24 | |
25 namespace cc { | |
26 namespace { | |
27 // We use a 16ms default frame interval because the rate at which the engine | |
28 // produces main frames doesn't matter. | |
29 base::TimeDelta kDefaultFrameInterval = base::TimeDelta::FromMilliseconds(16); | |
30 | |
31 static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number; | |
32 | |
33 bool ShouldUpdateLayer(Layer* layer) { | |
34 // If the embedder has marked the layer as non-drawable. | |
35 if (!layer->DrawsContent()) | |
36 return false; | |
37 | |
38 // If the layer bounds are empty. | |
39 if (layer->bounds().IsEmpty()) | |
40 return false; | |
41 | |
42 // If the layer is transparent and has no background filters applied. | |
43 // See EffectTree::UpdateIsDrawn for the logic details. | |
44 // A few things have been ignored: | |
45 // 1) We don't support threaded animations at the moment, so the opacity can | |
46 // not change on the client. | |
47 // 2) This does not account for layer hiding its subtree, but that is never | |
48 // used by the renderer. | |
49 // 3) Also updates a transparent layer's subtree when it will be skipped while | |
50 // drawing on the client. | |
51 if (layer->opacity() == 0.f && layer->background_filters().IsEmpty()) | |
52 return false; | |
53 | |
54 return true; | |
55 } | |
56 | |
57 } // namespace | |
58 | |
59 LayerTreeHostRemote::InitParams::InitParams() = default; | |
60 | |
61 LayerTreeHostRemote::InitParams::~InitParams() = default; | |
62 | |
63 LayerTreeHostRemote::LayerTreeHostRemote(InitParams* params) | |
64 : LayerTreeHostRemote( | |
65 params, | |
66 base::MakeUnique<LayerTree>(params->mutator_host, this)) {} | |
67 | |
68 LayerTreeHostRemote::LayerTreeHostRemote(InitParams* params, | |
69 std::unique_ptr<LayerTree> layer_tree) | |
70 : id_(s_layer_tree_host_sequence_number.GetNext() + 1), | |
71 main_frame_requested_from_bridge_(false), | |
72 client_(params->client), | |
73 task_runner_provider_( | |
74 TaskRunnerProvider::Create(std::move(params->main_task_runner), | |
75 nullptr)), | |
76 remote_compositor_bridge_(std::move(params->remote_compositor_bridge)), | |
77 engine_picture_cache_(std::move(params->engine_picture_cache)), | |
78 settings_(*params->settings), | |
79 layer_tree_(std::move(layer_tree)), | |
80 weak_factory_(this) { | |
81 DCHECK(task_runner_provider_->IsMainThread()); | |
82 DCHECK(remote_compositor_bridge_); | |
83 DCHECK(client_); | |
84 remote_compositor_bridge_->BindToClient(this); | |
85 layer_tree_->set_engine_picture_cache(engine_picture_cache_.get()); | |
86 } | |
87 | |
88 LayerTreeHostRemote::~LayerTreeHostRemote() = default; | |
89 | |
90 int LayerTreeHostRemote::GetId() const { | |
91 return id_; | |
92 } | |
93 | |
94 int LayerTreeHostRemote::SourceFrameNumber() const { | |
95 return source_frame_number_; | |
96 } | |
97 | |
98 LayerTree* LayerTreeHostRemote::GetLayerTree() { | |
99 return layer_tree_.get(); | |
100 } | |
101 | |
102 const LayerTree* LayerTreeHostRemote::GetLayerTree() const { | |
103 return layer_tree_.get(); | |
104 } | |
105 | |
106 UIResourceManager* LayerTreeHostRemote::GetUIResourceManager() const { | |
107 // We shouldn't need a UIResourceManager. The layers which need this | |
108 // (UIResourceLayers and PaintedScrollbarLayers) are never used by the | |
109 // renderer compositor in remote mode. | |
110 NOTREACHED() << "UIResourceManager requested. Unsupported Layer type used"; | |
111 return nullptr; | |
112 } | |
113 | |
114 TaskRunnerProvider* LayerTreeHostRemote::GetTaskRunnerProvider() const { | |
115 return task_runner_provider_.get(); | |
116 } | |
117 | |
118 const LayerTreeSettings& LayerTreeHostRemote::GetSettings() const { | |
119 return settings_; | |
120 } | |
121 | |
122 void LayerTreeHostRemote::SetFrameSinkId(const FrameSinkId& frame_sink_id) { | |
123 // We don't need to care about SurfaceLayers. The Surfaces system is | |
124 // relevant on the client only. | |
125 } | |
126 | |
127 void LayerTreeHostRemote::SetLayerTreeMutator( | |
128 std::unique_ptr<LayerTreeMutator> mutator) { | |
129 // TODO(khushalsagar): Compositor-worker not supported. See crbug.com/650876. | |
130 } | |
131 | |
132 void LayerTreeHostRemote::QueueSwapPromise( | |
133 std::unique_ptr<SwapPromise> swap_promise) { | |
134 swap_promise_manager_.QueueSwapPromise(std::move(swap_promise)); | |
135 } | |
136 | |
137 SwapPromiseManager* LayerTreeHostRemote::GetSwapPromiseManager() { | |
138 return &swap_promise_manager_; | |
139 } | |
140 | |
141 void LayerTreeHostRemote::SetHasGpuRasterizationTrigger(bool has_trigger) { | |
142 // TODO(khushalsagar) : Take care of Gpu raster. See crbug.com/650431. | |
143 } | |
144 | |
145 void LayerTreeHostRemote::SetVisible(bool visible) { | |
146 // The visibility of the compositor is controlled on the client, which is | |
147 // why this value is not sent there, since the client has the current true | |
148 // state. | |
149 visible_ = visible; | |
150 } | |
151 | |
152 bool LayerTreeHostRemote::IsVisible() const { | |
153 return visible_; | |
154 } | |
155 | |
156 void LayerTreeHostRemote::SetCompositorFrameSink( | |
157 std::unique_ptr<CompositorFrameSink> compositor_frame_sink) { | |
158 NOTREACHED() | |
159 << "The LayerTreeHostClient is never asked for a CompositorFrameSink"; | |
160 } | |
161 | |
162 std::unique_ptr<CompositorFrameSink> | |
163 LayerTreeHostRemote::ReleaseCompositorFrameSink() { | |
164 // Since we never have a CompositorFrameSink, this is always a no-op. | |
165 return nullptr; | |
166 } | |
167 | |
168 void LayerTreeHostRemote::SetNeedsAnimate() { | |
169 MainFrameRequested(FramePipelineStage::ANIMATE); | |
170 } | |
171 | |
172 void LayerTreeHostRemote::SetNeedsUpdateLayers() { | |
173 MainFrameRequested(FramePipelineStage::UPDATE_LAYERS); | |
174 } | |
175 | |
176 void LayerTreeHostRemote::SetNeedsCommit() { | |
177 MainFrameRequested(FramePipelineStage::COMMIT); | |
178 } | |
179 | |
180 void LayerTreeHostRemote::SetNeedsRecalculateRasterScales() { | |
181 // This is used by devtools to reraster content after changing device | |
182 // emulation modes, so doesn't need to be supported by Blimp. | |
183 } | |
184 | |
185 bool LayerTreeHostRemote::BeginMainFrameRequested() const { | |
186 return requested_pipeline_stage_for_next_frame_ != FramePipelineStage::NONE; | |
187 } | |
188 | |
189 bool LayerTreeHostRemote::CommitRequested() const { | |
190 // We report that a commit is in progress when synchronizing scroll and scale | |
191 // updates because in threaded mode, scroll/scale synchronization from the | |
192 // impl thread happens only during the main frame. | |
193 return synchronizing_client_updates_ || | |
194 requested_pipeline_stage_for_next_frame_ == FramePipelineStage::COMMIT; | |
195 } | |
196 | |
197 void LayerTreeHostRemote::SetDeferCommits(bool defer_commits) { | |
198 defer_commits_ = defer_commits; | |
199 ScheduleMainFrameIfNecessary(); | |
200 } | |
201 | |
202 void LayerTreeHostRemote::LayoutAndUpdateLayers() { | |
203 NOTREACHED() << "Only supported in single-threaded mode and this class" | |
204 << " does not support single-thread since it is out of process"; | |
205 } | |
206 | |
207 void LayerTreeHostRemote::Composite(base::TimeTicks frame_begin_time) { | |
208 NOTREACHED() << "Only supported in single-threaded mode and this class" | |
209 << " does not support single-thread since it is out of process"; | |
210 } | |
211 | |
212 void LayerTreeHostRemote::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { | |
213 // The engine shouldn't need to care about draws. CompositorFrames are never | |
214 // used here. | |
215 // TODO(khushalsagar): The caller could be waiting for an Ack for this redraw. | |
216 // We need a better solution for this. See crbug.com/651141. | |
217 NOTIMPLEMENTED(); | |
218 } | |
219 | |
220 void LayerTreeHostRemote::SetNextCommitForcesRedraw() { | |
221 // Ideally the engine shouldn't need to care about draw requests at all. The | |
222 // compositor that produces CompositorFrames is on the client and draw | |
223 // requests should be made directly to it on the client itself. | |
224 NOTIMPLEMENTED(); | |
225 } | |
226 | |
227 void LayerTreeHostRemote::NotifyInputThrottledUntilCommit() { | |
228 // This notification is used in the case where the renderer handles an input | |
229 // event, and needs to send an Ack to the browser when the resulting main | |
230 // frame is committed. If the compositor is taking too long on the pending | |
231 // tree, the commit processing will be delayed blocking all input as a result. | |
232 // So this is used to have the compositor activate the pending tree faster, so | |
233 // the pending commit can be processed. | |
234 // In remote mode, we don't send such notifications to the client because the | |
235 // most likely bottleneck is the transport instead of raster. Also, input is | |
236 // queued on the client, so if raster does end up being a bottleneck, the | |
237 // input handling code on the client informs the LayerTreeHostInProcess | |
238 // directly. | |
239 NOTIMPLEMENTED(); | |
240 } | |
241 | |
242 void LayerTreeHostRemote::UpdateBrowserControlsState( | |
243 BrowserControlsState constraints, | |
244 BrowserControlsState current, | |
245 bool animate) { | |
246 NOTREACHED() << "Using BrowserControls animations is not supported"; | |
247 } | |
248 | |
249 const base::WeakPtr<InputHandler>& LayerTreeHostRemote::GetInputHandler() | |
250 const { | |
251 // Input on the compositor thread is handled on the client, so this is always | |
252 // null. | |
253 return input_handler_weak_ptr_; | |
254 } | |
255 | |
256 void LayerTreeHostRemote::DidStopFlinging() { | |
257 // TODO(khushalsagar): This should not happen. See crbug.com/652000. | |
258 NOTIMPLEMENTED() << "We shouldn't be sending fling gestures to the engine"; | |
259 } | |
260 | |
261 void LayerTreeHostRemote::SetDebugState( | |
262 const LayerTreeDebugState& debug_state) { | |
263 // If any debugging needs to be enabled, ideally it should be using the | |
264 // compositor on the client directly. But the setup code will always set this | |
265 // on initialization, even if the settings end up being a no-op. | |
266 } | |
267 | |
268 const LayerTreeDebugState& LayerTreeHostRemote::GetDebugState() const { | |
269 return debug_state_; | |
270 } | |
271 | |
272 int LayerTreeHostRemote::ScheduleMicroBenchmark( | |
273 const std::string& benchmark_name, | |
274 std::unique_ptr<base::Value> value, | |
275 const MicroBenchmark::DoneCallback& callback) { | |
276 NOTREACHED(); | |
277 return 0; | |
278 } | |
279 | |
280 bool LayerTreeHostRemote::SendMessageToMicroBenchmark( | |
281 int id, | |
282 std::unique_ptr<base::Value> value) { | |
283 NOTREACHED(); | |
284 return false; | |
285 } | |
286 | |
287 SurfaceSequenceGenerator* LayerTreeHostRemote::GetSurfaceSequenceGenerator() { | |
288 // TODO(khushalsagar): Eliminate the use of this in blink. See | |
289 // crbug.com/650876. | |
290 return &surface_sequence_generator_; | |
291 } | |
292 | |
293 void LayerTreeHostRemote::SetNextCommitWaitsForActivation() { | |
294 // This is used only by layers that need resource synchronization, i.e., | |
295 // texture and surface layers, both of which are not supported. | |
296 NOTIMPLEMENTED() << "Unsupported Layer type used"; | |
297 } | |
298 | |
299 void LayerTreeHostRemote::ResetGpuRasterizationTracking() { | |
300 // TODO(khushalsagar): Take care of Gpu raster. See crbug.com/650431. | |
301 } | |
302 | |
303 void LayerTreeHostRemote::MainFrameRequested( | |
304 FramePipelineStage requested_pipeline_stage) { | |
305 DCHECK_NE(FramePipelineStage::NONE, requested_pipeline_stage); | |
306 | |
307 swap_promise_manager_.NotifySwapPromiseMonitorsOfSetNeedsCommit(); | |
308 | |
309 // If we are inside a main frame update right now and the requested pipeline | |
310 // stage is higher than the pipeline stage that we are at, then we'll get to | |
311 // in this main frame update itself. Update the | |
312 // |max_pipeline_stage_for_current_frame_| to ensure we go through the | |
313 // requested pipeline stage. | |
314 if (current_pipeline_stage_ != FramePipelineStage::NONE && | |
315 requested_pipeline_stage > current_pipeline_stage_) { | |
316 max_pipeline_stage_for_current_frame_ = std::max( | |
317 max_pipeline_stage_for_current_frame_, requested_pipeline_stage); | |
318 return; | |
319 } | |
320 | |
321 // Update the pipeline stage for the next frame and schedule an update if it | |
322 // has not been scheduled already. | |
323 requested_pipeline_stage_for_next_frame_ = std::max( | |
324 requested_pipeline_stage_for_next_frame_, requested_pipeline_stage); | |
325 | |
326 ScheduleMainFrameIfNecessary(); | |
327 } | |
328 | |
329 void LayerTreeHostRemote::ScheduleMainFrameIfNecessary() { | |
330 // If the client hasn't asked for a main frame, don't schedule one. | |
331 if (requested_pipeline_stage_for_next_frame_ == FramePipelineStage::NONE) | |
332 return; | |
333 | |
334 // If the client does not want us to run main frame updates right now, don't | |
335 // schedule one. | |
336 if (defer_commits_) | |
337 return; | |
338 | |
339 // If a main frame request is already pending with the | |
340 // RemoteCompositorBridge, we don't need to scheduler another one. | |
341 if (main_frame_requested_from_bridge_) | |
342 return; | |
343 | |
344 remote_compositor_bridge_->ScheduleMainFrame(); | |
345 main_frame_requested_from_bridge_ = true; | |
346 } | |
347 | |
348 void LayerTreeHostRemote::BeginMainFrame() { | |
349 DCHECK(main_frame_requested_from_bridge_); | |
350 DCHECK(task_runner_provider_->IsMainThread()); | |
351 | |
352 main_frame_requested_from_bridge_ = false; | |
353 | |
354 // The client might have suspended main frames in the meantime. Early out now, | |
355 // we'll come back here when they enable main frames again. | |
356 if (defer_commits_) | |
357 return; | |
358 | |
359 DCHECK_EQ(current_pipeline_stage_, FramePipelineStage::NONE); | |
360 DCHECK_EQ(max_pipeline_stage_for_current_frame_, FramePipelineStage::NONE); | |
361 DCHECK_NE(requested_pipeline_stage_for_next_frame_, FramePipelineStage::NONE); | |
362 | |
363 // Start the main frame. It should go till the requested pipeline stage. | |
364 max_pipeline_stage_for_current_frame_ = | |
365 requested_pipeline_stage_for_next_frame_; | |
366 requested_pipeline_stage_for_next_frame_ = FramePipelineStage::NONE; | |
367 | |
368 client_->WillBeginMainFrame(); | |
369 | |
370 current_pipeline_stage_ = FramePipelineStage::ANIMATE; | |
371 base::TimeTicks now = base::TimeTicks::Now(); | |
372 client_->BeginMainFrame(BeginFrameArgs::Create( | |
373 BEGINFRAME_FROM_HERE, begin_frame_source_.source_id(), | |
374 begin_frame_number_, now, now + kDefaultFrameInterval, | |
375 kDefaultFrameInterval, BeginFrameArgs::NORMAL)); | |
376 begin_frame_number_++; | |
377 // We don't run any animations on the layer because threaded animations are | |
378 // disabled. | |
379 // TODO(khushalsagar): Revisit this when adding support for animations. | |
380 client_->UpdateLayerTreeHost(); | |
381 | |
382 current_pipeline_stage_ = FramePipelineStage::UPDATE_LAYERS; | |
383 LayerList layer_list; | |
384 if (max_pipeline_stage_for_current_frame_ >= | |
385 FramePipelineStage::UPDATE_LAYERS) { | |
386 // Pull updates for all layers from the client. | |
387 // TODO(khushalsagar): Investigate the data impact from updating all the | |
388 // layers. See crbug.com/650885. | |
389 LayerTreeHostCommon::CallFunctionForEveryLayer( | |
390 layer_tree_.get(), [&layer_list](Layer* layer) { | |
391 if (!ShouldUpdateLayer(layer)) | |
392 return; | |
393 layer->SavePaintProperties(); | |
394 layer_list.push_back(layer); | |
395 }); | |
396 | |
397 bool content_is_suitable_for_gpu = false; | |
398 bool layers_updated = | |
399 layer_tree_->UpdateLayers(layer_list, &content_is_suitable_for_gpu); | |
400 | |
401 // If pulling layer updates resulted in any content updates, we need to go | |
402 // till the commit stage. | |
403 if (layers_updated) | |
404 max_pipeline_stage_for_current_frame_ = FramePipelineStage::COMMIT; | |
405 } | |
406 | |
407 current_pipeline_stage_ = FramePipelineStage::COMMIT; | |
408 client_->WillCommit(); | |
409 | |
410 if (max_pipeline_stage_for_current_frame_ < current_pipeline_stage_) { | |
411 // There is nothing to commit so break the swap promises. | |
412 swap_promise_manager_.BreakSwapPromises( | |
413 SwapPromise::DidNotSwapReason::COMMIT_NO_UPDATE); | |
414 | |
415 // For the client, the commit was successful. | |
416 MainFrameComplete(); | |
417 return; | |
418 } | |
419 | |
420 std::unique_ptr<CompositorProtoState> compositor_state = | |
421 base::MakeUnique<CompositorProtoState>(); | |
422 compositor_state->swap_promises = swap_promise_manager_.TakeSwapPromises(); | |
423 compositor_state->compositor_message = | |
424 base::MakeUnique<proto::CompositorMessage>(); | |
425 SerializeCurrentState( | |
426 compositor_state->compositor_message->mutable_layer_tree_host()); | |
427 remote_compositor_bridge_->ProcessCompositorStateUpdate( | |
428 std::move(compositor_state)); | |
429 | |
430 MainFrameComplete(); | |
431 | |
432 // We can not wait for updates dispatched from the client about the state of | |
433 // drawing or swaps for frames sent. Since these calls can be used by the | |
434 // LayerTreeHostClient to throttle further frame updates, so dispatch them | |
435 // right after the update is processed by the bridge. | |
436 // TODO(khushalsagar): We can not really know what these callbacks end up | |
437 // being used for. Consider migrating clients to understand/cope with the fact | |
438 // that there is no actual compositing happening here. | |
439 task_runner_provider_->MainThreadTaskRunner()->PostTask( | |
440 FROM_HERE, | |
441 base::Bind(&LayerTreeHostRemote::DispatchDrawAndSubmitCallbacks, | |
442 weak_factory_.GetWeakPtr())); | |
443 } | |
444 | |
445 void LayerTreeHostRemote::ApplyStateUpdateFromClient( | |
446 const proto::ClientStateUpdate& client_state_update) { | |
447 DCHECK(!synchronizing_client_updates_); | |
448 base::AutoReset<bool> synchronizing_updates(&synchronizing_client_updates_, | |
449 true); | |
450 | |
451 gfx::Vector2dF inner_viewport_delta; | |
452 for (int i = 0; i < client_state_update.scroll_updates_size(); ++i) { | |
453 const proto::ScrollUpdate& scroll_update = | |
454 client_state_update.scroll_updates(i); | |
455 int layer_id = scroll_update.layer_id(); | |
456 Layer* layer = layer_tree_->LayerById(layer_id); | |
457 gfx::Vector2dF scroll_delta = | |
458 ProtoToVector2dF(scroll_update.scroll_delta()); | |
459 | |
460 if (!layer) | |
461 continue; | |
462 | |
463 if (layer == layer_tree_->inner_viewport_scroll_layer()) { | |
464 inner_viewport_delta = scroll_delta; | |
465 } else { | |
466 layer->SetScrollOffsetFromImplSide( | |
467 gfx::ScrollOffsetWithDelta(layer->scroll_offset(), scroll_delta)); | |
468 SetNeedsUpdateLayers(); | |
469 } | |
470 } | |
471 | |
472 if (!inner_viewport_delta.IsZero()) { | |
473 layer_tree_->inner_viewport_scroll_layer()->SetScrollOffsetFromImplSide( | |
474 gfx::ScrollOffsetWithDelta( | |
475 layer_tree_->inner_viewport_scroll_layer()->scroll_offset(), | |
476 inner_viewport_delta)); | |
477 } | |
478 | |
479 float page_scale_delta = 1.0f; | |
480 if (client_state_update.has_page_scale_delta()) { | |
481 page_scale_delta = client_state_update.page_scale_delta(); | |
482 layer_tree_->SetPageScaleFromImplSide(layer_tree_->page_scale_factor() * | |
483 page_scale_delta); | |
484 } | |
485 | |
486 if (!inner_viewport_delta.IsZero() || page_scale_delta != 1.0f) { | |
487 client_->ApplyViewportDeltas(inner_viewport_delta, gfx::Vector2dF(), | |
488 gfx::Vector2dF(), page_scale_delta, 0.0f); | |
489 SetNeedsUpdateLayers(); | |
490 } | |
491 } | |
492 | |
493 void LayerTreeHostRemote::MainFrameComplete() { | |
494 DCHECK_EQ(current_pipeline_stage_, FramePipelineStage::COMMIT); | |
495 | |
496 current_pipeline_stage_ = FramePipelineStage::NONE; | |
497 max_pipeline_stage_for_current_frame_ = FramePipelineStage::NONE; | |
498 source_frame_number_++; | |
499 | |
500 client_->DidCommit(); | |
501 client_->DidBeginMainFrame(); | |
502 } | |
503 | |
504 void LayerTreeHostRemote::DispatchDrawAndSubmitCallbacks() { | |
505 client_->DidCommitAndDrawFrame(); | |
506 client_->DidReceiveCompositorFrameAck(); | |
507 } | |
508 | |
509 void LayerTreeHostRemote::SetTaskRunnerProviderForTesting( | |
510 std::unique_ptr<TaskRunnerProvider> task_runner_provider) { | |
511 task_runner_provider_ = std::move(task_runner_provider); | |
512 } | |
513 | |
514 void LayerTreeHostRemote::SerializeCurrentState( | |
515 proto::LayerTreeHost* layer_tree_host_proto) { | |
516 // Serialize the LayerTree. | |
517 layer_tree_->ToProtobuf(layer_tree_host_proto->mutable_layer_tree()); | |
518 | |
519 // Serialize the dirty layers. | |
520 std::unordered_set<Layer*> layers_need_push_properties; | |
521 layers_need_push_properties.swap( | |
522 layer_tree_->LayersThatShouldPushProperties()); | |
523 | |
524 for (auto* layer : layers_need_push_properties) { | |
525 proto::LayerProperties* layer_properties = | |
526 layer_tree_host_proto->mutable_layer_updates()->add_layers(); | |
527 layer->ToLayerPropertiesProto(layer_properties); | |
528 } | |
529 | |
530 std::vector<PictureData> pictures = | |
531 engine_picture_cache_->CalculateCacheUpdateAndFlush(); | |
532 proto::PictureDataVectorToSkPicturesProto( | |
533 pictures, layer_tree_host_proto->mutable_pictures()); | |
534 } | |
535 | |
536 } // namespace cc | |
OLD | NEW |