Chromium Code Reviews| Index: cc/blimp/layer_tree_host_remote.cc |
| diff --git a/cc/blimp/layer_tree_host_remote.cc b/cc/blimp/layer_tree_host_remote.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..94e0d05c6fc4c0882c80e7fa9aece58974bfe673 |
| --- /dev/null |
| +++ b/cc/blimp/layer_tree_host_remote.cc |
| @@ -0,0 +1,395 @@ |
| +// Copyright 2016 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. |
| + |
| +#include "cc/blimp/layer_tree_host_remote.h" |
| + |
| +#include "base/memory/ptr_util.h" |
| +#include "cc/animation/animation_host.h" |
| +#include "cc/blimp/compositor_proto_state.h" |
| +#include "cc/blimp/compositor_proto_state_sink.h" |
| +#include "cc/output/begin_frame_args.h" |
| +#include "cc/output/compositor_frame_sink.h" |
| +#include "cc/resources/ui_resource_manager.h" |
| +#include "cc/trees/layer_tree.h" |
| +#include "cc/trees/layer_tree_host_client.h" |
| +#include "cc/trees/layer_tree_host_common.h" |
| +#include "cc/trees/task_runner_provider.h" |
| + |
| +namespace cc { |
| +namespace { |
| +// We use a 16ms default frame interval because the rate at which the engine |
| +// produces main frames doesn't matter. |
| +base::TimeDelta kDefaultFrameInterval = base::TimeDelta::FromMilliseconds(16); |
| +} // namespace |
| + |
| +LayerTreeHostRemote::InitParams::InitParams() = default; |
| + |
| +LayerTreeHostRemote::InitParams::~InitParams() = default; |
| + |
| +LayerTreeHostRemote::LayerTreeHostRemote(InitParams* params) |
| + : LayerTreeHostRemote( |
| + params, |
| + base::MakeUnique<LayerTree>(std::move(params->animation_host), |
| + this)) {} |
| + |
| +LayerTreeHostRemote::LayerTreeHostRemote(InitParams* params, |
| + std::unique_ptr<LayerTree> layer_tree) |
| + : id_(LayerTreeHost::GenerateHostId()), |
| + source_frame_number_(0), |
| + visible_(false), |
| + defer_commits_(false), |
| + main_frame_requested_from_state_sink_(false), |
| + current_pipeline_stage_(FramePipelineStage::NONE), |
| + max_pipeline_stage_for_current_frame_(FramePipelineStage::NONE), |
| + requested_pipeline_stage_for_next_frame_(FramePipelineStage::NONE), |
| + client_(params->client), |
| + task_runner_provider_( |
| + TaskRunnerProvider::Create(std::move(params->main_task_runner), |
| + nullptr)), |
| + compositor_proto_state_sink_( |
| + std::move(params->compositor_proto_state_sink)), |
| + settings_(*params->settings), |
| + layer_tree_(std::move(layer_tree)), |
| + ui_resource_manager_(base::MakeUnique<UIResourceManager>()), |
|
danakj
2016/09/26 21:36:53
why is it a pointer?
Khushal
2016/09/27 01:07:49
I just did that because LTHInProcess also had a pt
|
| + weak_factory_(this) { |
| + DCHECK(task_runner_provider_->IsMainThread()); |
| + DCHECK(compositor_proto_state_sink_); |
| + DCHECK(client_); |
| + compositor_proto_state_sink_->BindToClient(this); |
| +} |
| + |
| +LayerTreeHostRemote::~LayerTreeHostRemote() = default; |
| + |
| +int LayerTreeHostRemote::GetId() const { |
| + return id_; |
| +} |
| + |
| +int LayerTreeHostRemote::SourceFrameNumber() const { |
| + return source_frame_number_; |
| +} |
| + |
| +LayerTree* LayerTreeHostRemote::GetLayerTree() { |
| + return layer_tree_.get(); |
| +} |
| + |
| +const LayerTree* LayerTreeHostRemote::GetLayerTree() const { |
| + return layer_tree_.get(); |
| +} |
| + |
| +UIResourceManager* LayerTreeHostRemote::GetUIResourceManager() const { |
| + // We shouldn't really need a UIResourceManager. The layers which need this |
| + // are never used. |
| + LOG(ERROR) << "UIResourceManager requested."; |
|
danakj
2016/09/26 21:36:52
How about notreached and return null then?
Khushal
2016/09/27 01:07:48
This is used by Painted scrollbars only, which bli
danakj
2016/09/27 20:32:43
My response would be "let's find out then" but I i
Khushal
2016/09/27 23:46:56
Okay, so we have turned turn off the use of Painte
|
| + return ui_resource_manager_.get(); |
| +} |
| + |
| +TaskRunnerProvider* LayerTreeHostRemote::GetTaskRunnerProvider() const { |
| + return task_runner_provider_.get(); |
| +} |
| + |
| +const LayerTreeSettings& LayerTreeHostRemote::GetSettings() const { |
| + return settings_; |
| +} |
| + |
| +void LayerTreeHostRemote::SetSurfaceClientId(uint32_t client_id) { |
| + // We don't need to care about SurfaceLayers. The Surfaces system is |
|
danakj
2016/09/26 21:36:52
Can we NOTREACHED?
Khushal
2016/09/27 01:07:49
The renderer will always call this still, even if
|
| + // relevant on the client only. |
| +} |
| + |
| +void LayerTreeHostRemote::SetLayerTreeMutator( |
| + std::unique_ptr<LayerTreeMutator> mutator) { |
| + // Compositor-worker not supported. |
|
danakj
2016/09/26 21:36:52
Can we NOTREACHED?
Khushal
2016/09/27 01:07:49
I think this is all setup code which will still ru
danakj
2016/09/27 20:32:43
Perhaps we should be turning the setup code off if
Khushal
2016/09/27 23:46:56
Sure, we can do it in blink also. For all the feat
|
| +} |
| + |
| +void LayerTreeHostRemote::QueueSwapPromise( |
| + std::unique_ptr<SwapPromise> swap_promise) { |
| + swap_promise_manager_.QueueSwapPromise(std::move(swap_promise)); |
| +} |
| + |
| +SwapPromiseManager* LayerTreeHostRemote::GetSwapPromiseManager() { |
| + return &swap_promise_manager_; |
| +} |
| + |
| +void LayerTreeHostRemote::SetHasGpuRasterizationTrigger(bool has_trigger) { |
| + // TODO(khushalsagar) : Take care of Gpu raster. |
|
danakj
2016/09/26 21:36:52
Can you point at a bug?
Khushal
2016/09/27 01:07:49
Done.
|
| +} |
| + |
| +void LayerTreeHostRemote::SetVisible(bool visible) { |
| + // The visibility is controlled on the client. The value here should always be |
| + // true and changes only during page transitions. |
|
danakj
2016/09/26 21:36:52
What do you mean by it should always be true? Call
Khushal
2016/09/27 01:07:49
I was just adding this comment to point out why we
|
| + visible_ = visible; |
| +} |
| + |
| +bool LayerTreeHostRemote::IsVisible() const { |
| + return visible_; |
| +} |
| + |
| +void LayerTreeHostRemote::SetCompositorFrameSink( |
| + std::unique_ptr<CompositorFrameSink> compositor_frame_sink) { |
| + NOTREACHED() << "We never ask the client for a CompositorFrameSink"; |
|
danakj
2016/09/26 21:36:53
"We" is a bit ambiguous here. "The LayerTreeHostCl
Khushal
2016/09/27 01:07:49
Done.
|
| +} |
| + |
| +std::unique_ptr<CompositorFrameSink> |
| +LayerTreeHostRemote::ReleaseCompositorFrameSink() { |
| + // Since we never have a CompositorFrameSink, this is always a no-op. |
|
danakj
2016/09/26 21:36:52
Can we NOTREACHED?
ps anything that is NOTREACHED
Khushal
2016/09/27 01:07:49
Well, the API says can be called safely anytime, s
danakj
2016/09/27 20:32:43
I thought this is only used by browser compositors
Khushal
2016/09/27 23:46:56
Its not there right now but I don't think its wron
|
| + return nullptr; |
| +} |
| + |
| +void LayerTreeHostRemote::SetNeedsAnimate() { |
| + MainFrameRequested(FramePipelineStage::ANIMATE); |
| +} |
| + |
| +void LayerTreeHostRemote::SetNeedsUpdateLayers() { |
| + MainFrameRequested(FramePipelineStage::UPDATE_LAYERS); |
| +} |
| + |
| +void LayerTreeHostRemote::SetNeedsCommit() { |
| + MainFrameRequested(FramePipelineStage::COMMIT); |
| +} |
| + |
| +bool LayerTreeHostRemote::BeginMainFrameRequested() const { |
| + return requested_pipeline_stage_for_next_frame_ != FramePipelineStage::NONE; |
| +} |
| + |
| +bool LayerTreeHostRemote::CommitRequested() const { |
| + return requested_pipeline_stage_for_next_frame_ == FramePipelineStage::COMMIT; |
| +} |
| + |
| +void LayerTreeHostRemote::SetDeferCommits(bool defer_commits) { |
| + defer_commits_ = defer_commits; |
| + ScheduleMainFrameIfNecessary(); |
| +} |
| + |
| +void LayerTreeHostRemote::LayoutAndUpdateLayers() { |
| + NOTREACHED() << "Only supported in single-threaded mode"; |
|
danakj
2016/09/26 21:36:52
".. and this class does not support single-thread
Khushal
2016/09/27 01:07:49
Done.
|
| +} |
| + |
| +void LayerTreeHostRemote::Composite(base::TimeTicks frame_begin_time) { |
| + NOTREACHED() << "Only supported in single-threaded mode"; |
|
danakj
2016/09/26 21:36:52
ditto
Khushal
2016/09/27 01:07:49
Done.
|
| +} |
| + |
| +void LayerTreeHostRemote::SetNeedsRedraw() { |
| + // The engine shouldn't need to care about draws. CompositorFrames are never |
|
danakj
2016/09/26 21:36:53
I don't know about this. This causes the composito
Khushal
2016/09/27 01:07:49
Its redundant in the blimp case. The RenderWidget
danakj
2016/09/27 20:32:43
Ok actually it looks like browser compositors (ui:
Khushal
2016/09/27 23:46:56
I would be happier to keep consistency with the th
danakj
2016/09/28 00:32:50
Leaving it empty feels like a landmine to me, I'd
Khushal
2016/09/28 19:47:16
Done. I'll remove it from the threaded one as well
|
| + // used here. |
| +} |
| + |
| +void LayerTreeHostRemote::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { |
| + // The engine shouldn't need to care about draws. CompositorFrames are never |
|
danakj
2016/09/26 21:36:52
Same.
danakj
2016/09/27 20:32:43
However RenderWidget calls this when it wants a re
Khushal
2016/09/27 23:46:56
Ah, good point. Thanks for pointing that case out.
danakj
2016/09/28 00:32:50
It sounds sketchy in that it's likely to interfere
Khushal
2016/09/28 19:47:16
In this case rather than the client, its elements
|
| + // used here. |
| +} |
| + |
| +void LayerTreeHostRemote::SetNextCommitForcesRedraw() { |
| + // The engine shouldn't need to care about draws. CompositorFrames are never |
|
danakj
2016/09/26 21:36:53
This is for testing, to ensure that it completes a
Khushal
2016/09/27 01:07:48
Still no need to send anything to the client thoug
danakj
2016/09/27 20:32:43
I guess it depends if you're running a pixel test.
Khushal
2016/09/27 23:46:56
For pixel tests my plan was to have an implementat
danakj
2016/09/28 00:32:50
I'm thinking more like gpu pixel tests: https://ww
Khushal
2016/09/28 19:47:16
Ah, okay. Can you point me to where this is done?
danakj
2016/09/29 23:59:35
Yes it's the screenshots thing. It's also interest
Khushal
2016/09/30 02:11:18
There is a super-basic complete end-to-end integra
|
| + // used here. |
| +} |
| + |
| +void LayerTreeHostRemote::NotifyInputThrottledUntilCommit() { |
| + // We don't throttle commits right now so this is not relevant. |
|
danakj
2016/09/26 21:36:52
NOTREACHED?
Khushal
2016/09/27 01:07:50
NOTIMPLEMENTED is better I think. The engine will
danakj
2016/09/27 20:32:43
OK I'm not actually sure how this will interact wi
Khushal
2016/09/27 23:46:56
So this was when I had looked at the code a while
danakj
2016/09/28 00:32:50
OK Cool that all sounds good, can you put this in
Khushal
2016/09/28 19:47:16
Done. Didn't add where on the client because that'
|
| +} |
| + |
| +void LayerTreeHostRemote::UpdateTopControlsState(TopControlsState constraints, |
| + TopControlsState current, |
| + bool animate) { |
| + NOTREACHED() << "Using TopControls animations is not supported"; |
| +} |
| + |
| +const base::WeakPtr<InputHandler>& LayerTreeHostRemote::GetInputHandler() |
| + const { |
| + // Input on the compositor thread is handled on the client, so this is always |
| + // null. |
| + return input_handler_weak_ptr_; |
|
danakj
2016/09/26 21:36:53
This is kinda awk, maybe follow up to make this re
Khushal
2016/09/27 01:07:49
Sounds good. I'll clean up in the next patch.
|
| +} |
| + |
| +void LayerTreeHostRemote::DidStopFlinging() { |
| + NOTIMPLEMENTED() << "We shouldn't be sending fling gestures to the engine"; |
| +} |
| + |
| +void LayerTreeHostRemote::SetDebugState( |
| + const LayerTreeDebugState& debug_state) { |
| + debug_state_ = debug_state; |
|
danakj
2016/09/26 21:36:53
How does this get to the client? Should it not Set
Khushal
2016/09/27 01:07:49
If there is a need to see debug info, then that ca
danakj
2016/09/27 20:32:43
Ok, why store it at all then?
How does inspector
Khushal
2016/09/27 23:46:56
Because things take a const&. I looked through the
danakj
2016/09/28 00:32:50
I can see why you made a member then, but why repl
Khushal
2016/09/28 19:47:16
Good point. I made it a NOTREACHED for now. Will c
|
| +} |
| + |
| +const LayerTreeDebugState& LayerTreeHostRemote::GetDebugState() const { |
| + return debug_state_; |
| +} |
| + |
| +int LayerTreeHostRemote::ScheduleMicroBenchmark( |
| + const std::string& benchmark_name, |
| + std::unique_ptr<base::Value> value, |
| + const MicroBenchmark::DoneCallback& callback) { |
| + NOTIMPLEMENTED(); |
|
danakj
2016/09/26 21:36:53
Or NOTREACHED?
Khushal
2016/09/27 01:07:49
I don't think we want to say that calling this met
danakj
2016/09/27 20:32:43
My thot is that if it doesn't work to use NOTREACH
Khushal
2016/09/27 23:46:56
Okay, you're right. This one's used by Gpu benchma
|
| + return 0; |
| +} |
| + |
| +bool LayerTreeHostRemote::SendMessageToMicroBenchmark( |
| + int id, |
| + std::unique_ptr<base::Value> value) { |
| + NOTIMPLEMENTED(); |
|
danakj
2016/09/26 21:36:53
Or NOTREACHED?
Khushal
2016/09/27 01:07:49
Same.
|
| + return false; |
| +} |
| + |
| +SurfaceSequenceGenerator* LayerTreeHostRemote::GetSurfaceSequenceGenerator() { |
| + return &surface_sequence_generator_; |
|
danakj
2016/09/26 21:36:53
This is for surfacelayer also like below. So why s
Khushal
2016/09/27 01:07:49
Yeah, it won't work. I still wasn't sure if I shou
danakj
2016/09/27 20:32:43
We shouldn't crash, the code that calls this shoul
Khushal
2016/09/27 23:46:56
Fair point. Added a TODO to turn this off in blink
|
| +} |
| + |
| +void LayerTreeHostRemote::SetNextCommitWaitsForActivation() { |
| + // This is used only by layers that need resource synchronization, i.e., |
| + // texture and surface layers, both of which are not supported. |
| + NOTIMPLEMENTED() << "Unsupported Layer type used"; |
| +} |
| + |
| +void LayerTreeHostRemote::ResetGpuRasterizationTracking() {} |
|
danakj
2016/09/26 21:36:52
TODO? Is there a bug to link to?
Khushal
2016/09/27 01:07:49
Done.
|
| + |
| +void LayerTreeHostRemote::MainFrameRequested( |
| + FramePipelineStage requested_pipeline_stage) { |
| + DCHECK_NE(FramePipelineStage::NONE, requested_pipeline_stage); |
| + |
| + swap_promise_manager_.NotifySwapPromiseMonitorsOfSetNeedsCommit(); |
| + |
| + // If we are inside a main frame update right now and the requested pipeline |
| + // stage is higher than the pipeline stage that we are at, then we'll get to |
| + // in this main frame update itself. Update the |
| + // |max_pipeline_stage_for_current_frame_| to ensure we go through the |
| + // requested pipeline stage. |
| + if (current_pipeline_stage_ != FramePipelineStage::NONE && |
| + requested_pipeline_stage > current_pipeline_stage_) { |
| + max_pipeline_stage_for_current_frame_ = std::max( |
| + max_pipeline_stage_for_current_frame_, requested_pipeline_stage); |
| + return; |
| + } |
| + |
| + // Update the pipeline stage for the next frame and schedule an update if it |
| + // has not been scheduled already. |
| + requested_pipeline_stage_for_next_frame_ = std::max( |
| + requested_pipeline_stage_for_next_frame_, requested_pipeline_stage); |
| + |
| + ScheduleMainFrameIfNecessary(); |
| +} |
| + |
| +void LayerTreeHostRemote::ScheduleMainFrameIfNecessary() { |
| + // If the client hasn't asked for a main frame, don't schedule one. |
| + if (requested_pipeline_stage_for_next_frame_ == FramePipelineStage::NONE) |
| + return; |
| + |
| + // If the client does not want us to run main frame updates right now, don't |
| + // schedule one. |
| + if (defer_commits_) |
| + return; |
| + |
| + // If a main frame request is already pending with the CompositorFrameSink, |
|
danakj
2016/09/26 21:36:53
I don't think you mean CompositorFrameSink
Khushal
2016/09/27 01:07:49
Done.
So I was hoping that this name wouldn't cau
|
| + // we don't need to scheduler another one. |
| + if (main_frame_requested_from_state_sink_) |
| + return; |
| + |
| + compositor_proto_state_sink_->ScheduleMainFrame(); |
| + main_frame_requested_from_state_sink_ = true; |
| +} |
| + |
| +void LayerTreeHostRemote::BeginMainFrame() { |
| + DCHECK(main_frame_requested_from_state_sink_); |
| + |
| + main_frame_requested_from_state_sink_ = false; |
| + |
| + // The client might have suspended main frames in the meantime. Early out now, |
| + // we'll come back here when they enable main frames again. |
| + if (defer_commits_) |
| + return; |
| + |
| + DCHECK_EQ(FramePipelineStage::NONE, current_pipeline_stage_); |
|
danakj
2016/09/26 21:36:52
can you write these in the same order you'd write
Khushal
2016/09/27 01:07:48
Done. I was actually looking for comments above th
|
| + DCHECK_EQ(FramePipelineStage::NONE, max_pipeline_stage_for_current_frame_); |
| + DCHECK_NE(FramePipelineStage::NONE, requested_pipeline_stage_for_next_frame_); |
| + |
| + // Start the main frame. It should go till the requested pipeline stage. |
| + max_pipeline_stage_for_current_frame_ = |
| + requested_pipeline_stage_for_next_frame_; |
| + requested_pipeline_stage_for_next_frame_ = FramePipelineStage::NONE; |
| + |
| + client_->WillBeginMainFrame(); |
| + |
| + current_pipeline_stage_ = FramePipelineStage::ANIMATE; |
| + base::TimeTicks now = base::TimeTicks::Now(); |
| + client_->BeginMainFrame(BeginFrameArgs::Create( |
| + BEGINFRAME_FROM_HERE, now, now + kDefaultFrameInterval, |
| + kDefaultFrameInterval, BeginFrameArgs::NORMAL)); |
| + // We don't run any animations on the layer because threaded animations are |
| + // disabled. |
| + // TODO(khushalsagar): Revisit this when adding support for animations. |
| + DCHECK(!layer_tree_->animation_host()->needs_push_properties()); |
| + client_->UpdateLayerTreeHost(); |
| + |
| + current_pipeline_stage_ = FramePipelineStage::UPDATE_LAYERS; |
| + LayerList layer_list; |
| + if (max_pipeline_stage_for_current_frame_ >= |
| + FramePipelineStage::UPDATE_LAYERS) { |
| + // Pull updates for all layers from the client. |
|
danakj
2016/09/26 21:36:53
Do you really want all layers? Is this something t
Khushal
2016/09/27 01:07:50
I'm glad you asked. So in the regular case we do h
danakj
2016/09/27 20:32:43
I think not optimizing this will make the initial
Khushal
2016/09/27 23:46:56
Thanks. Added a TODO.
|
| + LayerTreeHostCommon::CallFunctionForEveryLayer( |
| + layer_tree_.get(), |
| + [&layer_list](Layer* layer) { layer_list.push_back(layer); }); |
| + |
| + bool content_is_suitable_for_gpu = false; |
| + bool layers_updated = |
| + layer_tree_->UpdateLayers(layer_list, &content_is_suitable_for_gpu); |
| + |
| + // If pulling layer updates resulted in any content updates, we need to go |
| + // till the commit stage. |
| + max_pipeline_stage_for_current_frame_ = |
|
danakj
2016/09/26 21:36:52
This is a weird way to write
if (layers_updated)
Khushal
2016/09/27 01:07:49
Done.
|
| + layers_updated ? FramePipelineStage::COMMIT |
| + : max_pipeline_stage_for_current_frame_; |
| + } |
| + |
| + current_pipeline_stage_ = FramePipelineStage::COMMIT; |
| + client_->WillCommit(); |
| + |
| + if (max_pipeline_stage_for_current_frame_ < current_pipeline_stage_) { |
| + // There is nothing to commit so break the swap promises. |
| + swap_promise_manager_.BreakSwapPromises( |
| + SwapPromise::DidNotSwapReason::COMMIT_NO_UPDATE); |
| + |
| + // For the client, the commit was successful. |
| + MainFrameComplete(); |
| + return; |
| + } |
| + |
| + // TODO(khushalsagar): Serialize current state/reset dirty state tracking and |
| + // return the result to the state sink instead. |
| + std::unique_ptr<CompositorProtoState> compositor_state = |
| + base::MakeUnique<CompositorProtoState>(); |
| + compositor_proto_state_sink_->ProcessCompositorStateUpdate( |
| + std::move(compositor_state)); |
| + |
| + MainFrameComplete(); |
| + |
| + // We can not wait for updates dispatched from the client about the state of |
|
danakj
2016/09/26 21:36:53
Why can't you wait?
Khushal
2016/09/27 01:07:49
Because it used to end up throttling updates from
danakj
2016/09/27 20:32:43
OK Can you TODO pointing at a bug with this inform
Khushal
2016/09/27 23:46:56
Done.
|
| + // drawing or swaps for frames sent. Since these calls can be used by the |
| + // LayerTreeHostClient to throttle further frame updates, so dispatch them |
| + // right after the update is processed by the state sink. |
| + // TODO(khushalsagar): We can not really know what these callbacks end up |
| + // being used for. Consider migrating clients to understand/cope with the fact |
| + // that there is no actual compositing happening here. |
| + GetMainTaskRunner()->PostTask( |
| + FROM_HERE, base::Bind(&LayerTreeHostRemote::DispatchDrawAndSwapCallbacks, |
| + weak_factory_.GetWeakPtr())); |
| +} |
| + |
| +base::SingleThreadTaskRunner* LayerTreeHostRemote::GetMainTaskRunner() { |
| + return task_runner_provider_->MainThreadTaskRunner(); |
| +} |
| + |
| +void LayerTreeHostRemote::MainFrameComplete() { |
| + DCHECK_EQ(current_pipeline_stage_, FramePipelineStage::COMMIT); |
| + |
| + current_pipeline_stage_ = FramePipelineStage::NONE; |
| + max_pipeline_stage_for_current_frame_ = FramePipelineStage::NONE; |
| + source_frame_number_++; |
| + |
| + client_->DidCommit(); |
| + client_->DidBeginMainFrame(); |
| +} |
| + |
| +void LayerTreeHostRemote::DispatchDrawAndSwapCallbacks() { |
| + client_->DidCommitAndDrawFrame(); |
| + client_->DidCompleteSwapBuffers(); |
| +} |
| + |
| +} // namespace cc |