Commit 8d31bac4 authored by khushalsagar's avatar khushalsagar Committed by Commit bot

cc/blimp: Add a LayerTreeHostRemote implementation.

This sets up the framework for a LayerTreeHostRemote that implements
the LayerTreeHost API when the compositor is running across a network
boundary.

This change only sets the framework for running/scheduling main frame
updates and pushing the serialized state using the
CompositorProtoStateSink. Subsequent patches will add state
serialization.

BUG=648442
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_precise_blink_rel

Review-Url: https://codereview.chromium.org/2362073002
Cr-Commit-Position: refs/heads/master@{#422555}
parent 90d1a3f8
......@@ -43,12 +43,19 @@ component("cc") {
"animation/transform_operations.cc",
"animation/transform_operations.h",
"blimp/client_picture_cache.h",
"blimp/compositor_proto_state.cc",
"blimp/compositor_proto_state.h",
"blimp/engine_picture_cache.h",
"blimp/image_serialization_processor.h",
"blimp/layer_tree_host_remote.cc",
"blimp/layer_tree_host_remote.h",
"blimp/picture_data.cc",
"blimp/picture_data.h",
"blimp/picture_data_conversions.cc",
"blimp/picture_data_conversions.h",
"blimp/remote_compositor_bridge.cc",
"blimp/remote_compositor_bridge.h",
"blimp/remote_compositor_bridge_client.h",
"debug/benchmark_instrumentation.cc",
"debug/benchmark_instrumentation.h",
"debug/debug_colors.cc",
......@@ -664,6 +671,8 @@ static_library("test_support") {
"test/fake_raster_source.h",
"test/fake_recording_source.cc",
"test/fake_recording_source.h",
"test/fake_remote_compositor_bridge.cc",
"test/fake_remote_compositor_bridge.h",
"test/fake_rendering_stats_instrumentation.h",
"test/fake_resource_provider.h",
"test/fake_scoped_ui_resource.cc",
......@@ -829,6 +838,7 @@ test("cc_unittests") {
"base/spiral_iterator_unittest.cc",
"base/tiling_data_unittest.cc",
"base/unique_notifier_unittest.cc",
"blimp/layer_tree_host_remote_unittest.cc",
"blimp/picture_data_conversions_unittest.cc",
"debug/layer_tree_debug_state_unittest.cc",
"debug/micro_benchmark_controller_unittest.cc",
......
// 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/compositor_proto_state.h"
#include "cc/output/swap_promise.h"
namespace cc {
CompositorProtoState::CompositorProtoState() = default;
CompositorProtoState::~CompositorProtoState() = default;
} // namespace cc
// 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.
#ifndef CC_BLIMP_COMPOSITOR_PROTO_STATE_H_
#define CC_BLIMP_COMPOSITOR_PROTO_STATE_H_
#include <vector>
#include "base/macros.h"
#include "cc/base/cc_export.h"
namespace cc {
class SwapPromise;
class CC_EXPORT CompositorProtoState {
public:
CompositorProtoState();
~CompositorProtoState();
// The SwapPromises associated with this frame update.
std::vector<SwapPromise> swap_promises;
// TODO(khushalsagar): Add serialized representation of the layers, layer tree
// and display lists.
private:
DISALLOW_COPY_AND_ASSIGN(CompositorProtoState);
};
} // namespace cc
#endif // CC_BLIMP_COMPOSITOR_PROTO_STATE_H_
// 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/atomic_sequence_num.h"
#include "base/memory/ptr_util.h"
#include "cc/animation/animation_host.h"
#include "cc/blimp/compositor_proto_state.h"
#include "cc/blimp/remote_compositor_bridge.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/compositor_frame_sink.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);
static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number;
} // 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_(s_layer_tree_host_sequence_number.GetNext() + 1),
main_frame_requested_from_bridge_(false),
client_(params->client),
task_runner_provider_(
TaskRunnerProvider::Create(std::move(params->main_task_runner),
nullptr)),
remote_compositor_bridge_(std::move(params->remote_compositor_bridge)),
settings_(*params->settings),
layer_tree_(std::move(layer_tree)),
weak_factory_(this) {
DCHECK(task_runner_provider_->IsMainThread());
DCHECK(remote_compositor_bridge_);
DCHECK(client_);
remote_compositor_bridge_->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 need a UIResourceManager. The layers which need this
// (UIResourceLayers and PaintedScrollbarLayers) are never used by the
// renderer compositor in remote mode.
NOTREACHED() << "UIResourceManager requested. Unsupported Layer type used";
return nullptr;
}
TaskRunnerProvider* LayerTreeHostRemote::GetTaskRunnerProvider() const {
return task_runner_provider_.get();
}
const LayerTreeSettings& LayerTreeHostRemote::GetSettings() const {
return settings_;
}
void LayerTreeHostRemote::SetFrameSinkId(const FrameSinkId& frame_sink_id) {
// We don't need to care about SurfaceLayers. The Surfaces system is
// relevant on the client only.
}
void LayerTreeHostRemote::SetLayerTreeMutator(
std::unique_ptr<LayerTreeMutator> mutator) {
// TODO(khushalsagar): Compositor-worker not supported. See crbug.com/650876.
}
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. See crbug.com/650431.
}
void LayerTreeHostRemote::SetVisible(bool visible) {
// The visibility of the compositor is controlled on the client, which is
// why this value is not sent there, since the client has the current true
// state.
visible_ = visible;
}
bool LayerTreeHostRemote::IsVisible() const {
return visible_;
}
void LayerTreeHostRemote::SetCompositorFrameSink(
std::unique_ptr<CompositorFrameSink> compositor_frame_sink) {
NOTREACHED()
<< "The LayerTreeHostClient is never asked for a CompositorFrameSink";
}
std::unique_ptr<CompositorFrameSink>
LayerTreeHostRemote::ReleaseCompositorFrameSink() {
// Since we never have a CompositorFrameSink, this is always a no-op.
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 and this class"
<< " does not support single-thread since it is out of process";
}
void LayerTreeHostRemote::Composite(base::TimeTicks frame_begin_time) {
NOTREACHED() << "Only supported in single-threaded mode and this class"
<< " does not support single-thread since it is out of process";
}
void LayerTreeHostRemote::SetNeedsRedraw() {
// The engine shouldn't need to care about draws. CompositorFrames are never
// used here.
NOTREACHED();
}
void LayerTreeHostRemote::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
// The engine shouldn't need to care about draws. CompositorFrames are never
// used here.
// TODO(khushalsagar): The caller could be waiting for an Ack for this redraw.
// We need a better solution for this. See crbug.com/651141.
NOTIMPLEMENTED();
}
void LayerTreeHostRemote::SetNextCommitForcesRedraw() {
// Ideally the engine shouldn't need to care about draw requests at all. The
// compositor that produces CompositorFrames is on the client and draw
// requests should be made directly to it on the client itself.
NOTREACHED();
}
void LayerTreeHostRemote::NotifyInputThrottledUntilCommit() {
// This notification is used in the case where the renderer handles an input
// event, and needs to send an Ack to the browser when the resulting main
// frame is committed. If the compositor is taking too long on the pending
// tree, the commit processing will be delayed blocking all input as a result.
// So this is used to have the compositor activate the pending tree faster, so
// the pending commit can be processed.
// In remote mode, we don't send such notifications to the client because the
// most likely bottleneck is the transport instead of raster. Also, input is
// queued on the client, so if raster does end up being a bottleneck, the
// input handling code on the client informs the LayerTreeHostInProcess
// directly.
NOTIMPLEMENTED();
}
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_;
}
void LayerTreeHostRemote::DidStopFlinging() {
// TODO(khushalsagar): This should not happen. See crbug.com/652000.
NOTIMPLEMENTED() << "We shouldn't be sending fling gestures to the engine";
}
void LayerTreeHostRemote::SetDebugState(
const LayerTreeDebugState& debug_state) {
// TODO(khushalsagar): Figure out if we need to send these to the client.
NOTREACHED();
}
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) {
NOTREACHED();
return 0;
}
bool LayerTreeHostRemote::SendMessageToMicroBenchmark(
int id,
std::unique_ptr<base::Value> value) {
NOTREACHED();
return false;
}
SurfaceSequenceGenerator* LayerTreeHostRemote::GetSurfaceSequenceGenerator() {
// TODO(khushalsagar): Eliminate the use of this in blink. See
// crbug.com/650876.
return &surface_sequence_generator_;
}
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() {
// TODO(khushalsagar): Take care of Gpu raster. See crbug.com/650431.
}
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
// RemoteCompositorBridge, we don't need to scheduler another one.
if (main_frame_requested_from_bridge_)
return;
remote_compositor_bridge_->ScheduleMainFrame();
main_frame_requested_from_bridge_ = true;
}
void LayerTreeHostRemote::BeginMainFrame() {
DCHECK(main_frame_requested_from_bridge_);
DCHECK(task_runner_provider_->IsMainThread());
main_frame_requested_from_bridge_ = 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(current_pipeline_stage_, FramePipelineStage::NONE);
DCHECK_EQ(max_pipeline_stage_for_current_frame_, FramePipelineStage::NONE);
DCHECK_NE(requested_pipeline_stage_for_next_frame_, FramePipelineStage::NONE);
// 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.
// TODO(khushalsagar): Investigate the data impact from updating all the
// layers. See crbug.com/650885.
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.
if (layers_updated)
max_pipeline_stage_for_current_frame_ = FramePipelineStage::COMMIT;
}
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 bridge instead.
std::unique_ptr<CompositorProtoState> compositor_state =
base::MakeUnique<CompositorProtoState>();
remote_compositor_bridge_->ProcessCompositorStateUpdate(
std::move(compositor_state));
MainFrameComplete();
// We can not wait for updates dispatched from the client about the state of
// 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 bridge.
// 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.
task_runner_provider_->MainThreadTaskRunner()->PostTask(
FROM_HERE, base::Bind(&LayerTreeHostRemote::DispatchDrawAndSwapCallbacks,
weak_factory_.GetWeakPtr()));
}
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
// 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.
#ifndef CC_BLIMP_LAYER_TREE_HOST_REMOTE_H_
#define CC_BLIMP_LAYER_TREE_HOST_REMOTE_H_
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "cc/base/cc_export.h"
#include "cc/blimp/remote_compositor_bridge_client.h"
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_settings.h"
#include "cc/trees/surface_sequence_generator.h"
#include "cc/trees/swap_promise_manager.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace cc {
class AnimationHost;
class RemoteCompositorBridge;
class LayerTreeHostClient;
class CC_EXPORT LayerTreeHostRemote : public LayerTreeHost,
public RemoteCompositorBridgeClient {
public:
struct CC_EXPORT InitParams {
LayerTreeHostClient* client = nullptr;
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner;
std::unique_ptr<AnimationHost> animation_host;
std::unique_ptr<RemoteCompositorBridge> remote_compositor_bridge;
LayerTreeSettings const* settings = nullptr;
InitParams();
~InitParams();
};
explicit LayerTreeHostRemote(InitParams* params);
~LayerTreeHostRemote() override;
// LayerTreeHost implementation.
int GetId() const override;
int SourceFrameNumber() const override;
LayerTree* GetLayerTree() override;
const LayerTree* GetLayerTree() const override;
UIResourceManager* GetUIResourceManager() const override;
TaskRunnerProvider* GetTaskRunnerProvider() const override;
const LayerTreeSettings& GetSettings() const override;
void SetFrameSinkId(const FrameSinkId& frame_sink_id) override;
void SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
void QueueSwapPromise(std::unique_ptr<SwapPromise> swap_promise) override;
SwapPromiseManager* GetSwapPromiseManager() override;
void SetHasGpuRasterizationTrigger(bool has_trigger) override;
void SetVisible(bool visible) override;
bool IsVisible() const override;
void SetCompositorFrameSink(
std::unique_ptr<CompositorFrameSink> compositor_frame_sink) override;
std::unique_ptr<CompositorFrameSink> ReleaseCompositorFrameSink() override;
void SetNeedsAnimate() override;
void SetNeedsUpdateLayers() override;
void SetNeedsCommit() override;
bool BeginMainFrameRequested() const override;
bool CommitRequested() const override;
void SetDeferCommits(bool defer_commits) override;
void LayoutAndUpdateLayers() override;
void Composite(base::TimeTicks frame_begin_time) override;
void SetNeedsRedraw() override;
void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
void SetNextCommitForcesRedraw() override;
void NotifyInputThrottledUntilCommit() override;
void UpdateTopControlsState(TopControlsState constraints,
TopControlsState current,
bool animate) override;
const base::WeakPtr<InputHandler>& GetInputHandler() const override;
void DidStopFlinging() override;
void SetDebugState(const LayerTreeDebugState& debug_state) override;
const LayerTreeDebugState& GetDebugState() const override;
int ScheduleMicroBenchmark(
const std::string& benchmark_name,
std::unique_ptr<base::Value> value,
const MicroBenchmark::DoneCallback& callback) override;
bool SendMessageToMicroBenchmark(int id,
std::unique_ptr<base::Value> value) override;
SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() override;
void SetNextCommitWaitsForActivation() override;
void ResetGpuRasterizationTracking() override;
protected:
// Protected for testing. Allows tests to inject the LayerTree.
LayerTreeHostRemote(InitParams* params,
std::unique_ptr<LayerTree> layer_tree);
private:
enum class FramePipelineStage { NONE, ANIMATE, UPDATE_LAYERS, COMMIT };
// RemoteCompositorBridgeClient implementation.
void BeginMainFrame() override;
void MainFrameRequested(FramePipelineStage requested_pipeline_stage);
void ScheduleMainFrameIfNecessary();
void MainFrameComplete();
void DispatchDrawAndSwapCallbacks();
const int id_;
int source_frame_number_ = 0;
bool visible_ = false;
bool defer_commits_ = false;
// Set to true if a main frame request is pending on the
// RemoteCompositorBridge.
bool main_frame_requested_from_bridge_ = false;
// Set to the pipeline stage we are currently at if we are inside a main frame
// update.
FramePipelineStage current_pipeline_stage_ = FramePipelineStage::NONE;
// Set to the pipeline stage we need to go to for the current main frame
// update, if we are inside a main frame update.
FramePipelineStage max_pipeline_stage_for_current_frame_ =
FramePipelineStage::NONE;
// Set to the pipeline stage requested for the next BeginMainFrame.
FramePipelineStage requested_pipeline_stage_for_next_frame_ =
FramePipelineStage::NONE;
LayerTreeHostClient* client_;
std::unique_ptr<TaskRunnerProvider> task_runner_provider_;
// The RemoteCompositorBridge used to submit frame updates to the client.
std::unique_ptr<RemoteCompositorBridge> remote_compositor_bridge_;
LayerTreeSettings settings_;
LayerTreeDebugState debug_state_;
// The LayerTree holds the root layer and other state on the engine.
std::unique_ptr<LayerTree> layer_tree_;
SwapPromiseManager swap_promise_manager_;
SurfaceSequenceGenerator surface_sequence_generator_;
base::WeakPtr<InputHandler> input_handler_weak_ptr_;
base::WeakPtrFactory<LayerTreeHostRemote> weak_factory_;
};
} // namespace cc
#endif // CC_BLIMP_LAYER_TREE_HOST_REMOTE_H_
// 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/bind.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/layers/layer.h"
#include "cc/output/begin_frame_args.h"
#include "cc/test/fake_remote_compositor_bridge.h"
#include "cc/test/stub_layer_tree_host_client.h"
#include "cc/trees/layer_tree_settings.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using testing::InSequence;
using testing::Mock;
using testing::StrictMock;
#define EXPECT_BEGIN_MAIN_FRAME(client, num) \
EXPECT_CALL(client, WillBeginMainFrame()).Times(num); \
EXPECT_CALL(client, BeginMainFrame(_)).Times(num); \
EXPECT_CALL(client, DidUpdateLayerTreeHost()).Times(num); \
EXPECT_CALL(client, WillCommit()).Times(num); \
EXPECT_CALL(client, DidCommit()).Times(num); \
EXPECT_CALL(client, DidBeginMainFrame()).Times(num);
#define EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(client, num) \
EXPECT_BEGIN_MAIN_FRAME(client, num) \
EXPECT_CALL(client, DidCommitAndDrawFrame()).Times(num); \
EXPECT_CALL(client, DidCompleteSwapBuffers()).Times(num);
namespace cc {
namespace {
class UpdateTrackingRemoteCompositorBridge : public FakeRemoteCompositorBridge {
public:
UpdateTrackingRemoteCompositorBridge(
scoped_refptr<base::SingleThreadTaskRunner> compositor_main_task_runner)
: FakeRemoteCompositorBridge(std::move(compositor_main_task_runner)) {}
~UpdateTrackingRemoteCompositorBridge() override = default;
void ProcessCompositorStateUpdate(
std::unique_ptr<CompositorProtoState> compositor_proto_state) override {
num_updates_received_++;
};
int num_updates_received() const { return num_updates_received_; }
private:
int num_updates_received_ = 0;
};
class MockLayerTreeHostClient : public StubLayerTreeHostClient {
public:
MockLayerTreeHostClient() = default;
~MockLayerTreeHostClient() override = default;
void set_update_host_callback(base::Closure callback) {
update_host_callback_ = callback;
}
void UpdateLayerTreeHost() override {
update_host_callback_.Run();
DidUpdateLayerTreeHost();
}
// LayerTreeHostClient implementation.
MOCK_METHOD0(WillBeginMainFrame, void());
MOCK_METHOD1(BeginMainFrame, void(const BeginFrameArgs& args));
MOCK_METHOD0(DidBeginMainFrame, void());
MOCK_METHOD0(DidUpdateLayerTreeHost, void());
MOCK_METHOD0(WillCommit, void());
MOCK_METHOD0(DidCommit, void());
MOCK_METHOD0(DidCommitAndDrawFrame, void());
MOCK_METHOD0(DidCompleteSwapBuffers, void());
private:
base::Closure update_host_callback_;
};
class MockLayer : public Layer {
public:
explicit MockLayer(bool update) : update_(update) {}
bool Update() override {
did_update_ = true;
return update_;
}
bool did_update() const { return did_update_; }
private:
~MockLayer() override {}
bool update_;
bool did_update_ = false;
};
class MockLayerTree : public LayerTree {
public:
MockLayerTree(std::unique_ptr<AnimationHost> animation_host,
LayerTreeHost* layer_tree_host)
: LayerTree(std::move(animation_host), layer_tree_host) {}
~MockLayerTree() override {}
// We don't want tree sync requests to trigger commits.
void SetNeedsFullTreeSync() override {}
};
class LayerTreeHostRemoteForTesting : public LayerTreeHostRemote {
public:
explicit LayerTreeHostRemoteForTesting(InitParams* params)
: LayerTreeHostRemote(
params,
base::MakeUnique<MockLayerTree>(AnimationHost::CreateMainInstance(),
this)) {}
~LayerTreeHostRemoteForTesting() override {}
};
class LayerTreeHostRemoteTest : public testing::Test {
public:
LayerTreeHostRemoteTest() {
mock_layer_tree_host_client_.set_update_host_callback(base::Bind(
&LayerTreeHostRemoteTest::UpdateLayerTreeHost, base::Unretained(this)));
}
~LayerTreeHostRemoteTest() override {}
void SetUp() override {
LayerTreeHostRemote::InitParams params;
params.client = &mock_layer_tree_host_client_;
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner =
base::ThreadTaskRunnerHandle::Get();
params.main_task_runner = main_task_runner;
std::unique_ptr<UpdateTrackingRemoteCompositorBridge>
remote_compositor_bridge =
base::MakeUnique<UpdateTrackingRemoteCompositorBridge>(
main_task_runner);
remote_compositor_bridge_ = remote_compositor_bridge.get();
params.remote_compositor_bridge = std::move(remote_compositor_bridge);
LayerTreeSettings settings;
params.settings = &settings;
layer_tree_host_ = base::MakeUnique<LayerTreeHostRemoteForTesting>(&params);
root_layer_ = make_scoped_refptr(new MockLayer(false));
layer_tree_host_->GetLayerTree()->SetRootLayer(root_layer_);
}
void TearDown() override {
Mock::VerifyAndClearExpectations(&mock_layer_tree_host_client_);
layer_tree_host_ = nullptr;
root_layer_ = nullptr;
remote_compositor_bridge_ = nullptr;
}
void UpdateLayerTreeHost() {
if (needs_animate_during_main_frame_) {
layer_tree_host_->SetNeedsAnimate();
needs_animate_during_main_frame_ = false;
}
if (needs_commit_during_main_frame_) {
layer_tree_host_->SetNeedsCommit();
needs_commit_during_main_frame_ = false;
}
}
void set_needs_animate_during_main_frame(bool needs) {
needs_animate_during_main_frame_ = needs;
}
void set_needs_commit_during_main_frame(bool needs) {
needs_commit_during_main_frame_ = needs;
}
protected:
std::unique_ptr<LayerTreeHostRemote> layer_tree_host_;
StrictMock<MockLayerTreeHostClient> mock_layer_tree_host_client_;
UpdateTrackingRemoteCompositorBridge* remote_compositor_bridge_ = nullptr;
scoped_refptr<MockLayer> root_layer_;
bool needs_animate_during_main_frame_ = false;
bool needs_commit_during_main_frame_ = false;
private:
DISALLOW_COPY_AND_ASSIGN(LayerTreeHostRemoteTest);
};
TEST_F(LayerTreeHostRemoteTest, BeginMainFrameAnimateOnly) {
// The main frame should run until the animate step only.
InSequence s;
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME(mock_layer_tree_host_client_, num_of_frames);
int previous_source_frame = layer_tree_host_->SourceFrameNumber();
layer_tree_host_->SetNeedsAnimate();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(root_layer_->did_update());
EXPECT_EQ(0, remote_compositor_bridge_->num_updates_received());
EXPECT_EQ(++previous_source_frame, layer_tree_host_->SourceFrameNumber());
}
TEST_F(LayerTreeHostRemoteTest, BeginMainFrameUpdateLayers) {
// The main frame should run until the update layers step only.
InSequence s;
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME(mock_layer_tree_host_client_, num_of_frames);
int previous_source_frame = layer_tree_host_->SourceFrameNumber();
layer_tree_host_->SetNeedsUpdateLayers();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(0, remote_compositor_bridge_->num_updates_received());
EXPECT_EQ(++previous_source_frame, layer_tree_host_->SourceFrameNumber());
}
TEST_F(LayerTreeHostRemoteTest, BeginMainFrameCommit) {
// The main frame should run until the commit step.
InSequence s;
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(mock_layer_tree_host_client_,
num_of_frames);
int previous_source_frame = layer_tree_host_->SourceFrameNumber();
layer_tree_host_->SetNeedsCommit();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(1, remote_compositor_bridge_->num_updates_received());
EXPECT_EQ(++previous_source_frame, layer_tree_host_->SourceFrameNumber());
}
TEST_F(LayerTreeHostRemoteTest, BeginMainFrameMultipleRequests) {
// Multiple BeginMainFrame requests should result in a single main frame
// update.
InSequence s;
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(mock_layer_tree_host_client_,
num_of_frames);
layer_tree_host_->SetNeedsAnimate();
layer_tree_host_->SetNeedsUpdateLayers();
layer_tree_host_->SetNeedsCommit();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(1, remote_compositor_bridge_->num_updates_received());
}
TEST_F(LayerTreeHostRemoteTest, CommitRequestThenDeferCommits) {
// Make a commit request, followed by a request to defer commits.
layer_tree_host_->SetNeedsCommit();
layer_tree_host_->SetDeferCommits(true);
// We should not have seen any BeginMainFrames.
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(&mock_layer_tree_host_client_);
EXPECT_FALSE(root_layer_->did_update());
EXPECT_EQ(0, remote_compositor_bridge_->num_updates_received());
// Now enable commits and ensure we see a BeginMainFrame.
layer_tree_host_->SetDeferCommits(false);
InSequence s;
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(mock_layer_tree_host_client_,
num_of_frames);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(1, remote_compositor_bridge_->num_updates_received());
}
TEST_F(LayerTreeHostRemoteTest, DeferCommitsThenCommitRequest) {
// Defer commits followed by a commit request.
layer_tree_host_->SetDeferCommits(true);
layer_tree_host_->SetNeedsCommit();
// We should not have seen any BeginMainFrames.
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClearExpectations(&mock_layer_tree_host_client_);
EXPECT_FALSE(root_layer_->did_update());
EXPECT_EQ(0, remote_compositor_bridge_->num_updates_received());
// Now enable commits and ensure we see a BeginMainFrame.
layer_tree_host_->SetDeferCommits(false);
InSequence s;
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(mock_layer_tree_host_client_,
num_of_frames);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(1, remote_compositor_bridge_->num_updates_received());
}
TEST_F(LayerTreeHostRemoteTest, RequestAnimateDuringMainFrame) {
// An animate request during BeginMainFrame should result in a second main
// frame being scheduled.
set_needs_animate_during_main_frame(true);
int num_of_frames = 2;
EXPECT_BEGIN_MAIN_FRAME(mock_layer_tree_host_client_, num_of_frames);
layer_tree_host_->SetNeedsAnimate();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(root_layer_->did_update());
EXPECT_EQ(0, remote_compositor_bridge_->num_updates_received());
}
TEST_F(LayerTreeHostRemoteTest, RequestCommitDuringMainFrame) {
// A commit request during a BeginMainFrame scheduled for an animate request
// should go till the commit stage.
set_needs_commit_during_main_frame(true);
int num_of_frames = 1;
EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(mock_layer_tree_host_client_,
num_of_frames);
layer_tree_host_->SetNeedsAnimate();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(1, remote_compositor_bridge_->num_updates_received());
}
TEST_F(LayerTreeHostRemoteTest, RequestCommitDuringLayerUpdates) {
// A layer update during a main frame should result in a commit.
scoped_refptr<Layer> child_layer = make_scoped_refptr(new MockLayer(true));
root_layer_->AddChild(child_layer);
EXPECT_BEGIN_MAIN_FRAME_AND_COMMIT(mock_layer_tree_host_client_, 1);
layer_tree_host_->SetNeedsUpdateLayers();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(root_layer_->did_update());
EXPECT_EQ(1, remote_compositor_bridge_->num_updates_received());
}
} // namespace
} // namespace cc
// 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/remote_compositor_bridge.h"
#include "base/single_thread_task_runner.h"
namespace cc {
RemoteCompositorBridge::RemoteCompositorBridge(
scoped_refptr<base::SingleThreadTaskRunner> compositor_main_task_runner)
: compositor_main_task_runner_(std::move(compositor_main_task_runner)) {}
RemoteCompositorBridge::~RemoteCompositorBridge() = default;
} // namespace cc
// 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.
#ifndef CC_BLIMP_REMOTE_COMPOSITOR_BRIDGE_H_
#define CC_BLIMP_REMOTE_COMPOSITOR_BRIDGE_H_
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "cc/base/cc_export.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace cc {
class CompositorProtoState;
class RemoteCompositorBridgeClient;
// The RemoteCompositorBridge is the remote LTH's communication bridge to the
// compositor on the client that consumes the CompositorProtoState updates and
// performs the actual compositing work. It is responsible for scheduling
// when a state update should be sent to the client and providing back
// mutations made to the state on the client.
class CC_EXPORT RemoteCompositorBridge {
public:
RemoteCompositorBridge(
scoped_refptr<base::SingleThreadTaskRunner> compositor_main_task_runner);
virtual ~RemoteCompositorBridge();
// Must be called exactly once before the RemoteCompositorBridge can be
// used. Once bound, the client is expected to outlive this class.
virtual void BindToClient(RemoteCompositorBridgeClient* client) = 0;
// Notifies the bridge that a main frame update is required.
virtual void ScheduleMainFrame() = 0;
// If a main frame update results in any mutations to the compositor state,
// the serialized compositor state is provided to the
// RemoteCompositorBridge.
virtual void ProcessCompositorStateUpdate(
std::unique_ptr<CompositorProtoState> compositor_proto_state) = 0;
protected:
// The task runner for the compositor's main thread. The
// RemoteCompositorBridgeClient must be called on this task runner.
scoped_refptr<base::SingleThreadTaskRunner> compositor_main_task_runner_;
private:
DISALLOW_COPY_AND_ASSIGN(RemoteCompositorBridge);
};
} // namespace cc
#endif // CC_BLIMP_REMOTE_COMPOSITOR_BRIDGE_H_
// 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.
#ifndef CC_BLIMP_REMOTE_COMPOSITOR_BRIDGE_CLIENT_H_
#define CC_BLIMP_REMOTE_COMPOSITOR_BRIDGE_CLIENT_H_
#include "base/macros.h"
#include "cc/base/cc_export.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace cc {
class CompositorProtoState;
class CC_EXPORT RemoteCompositorBridgeClient {
public:
virtual ~RemoteCompositorBridgeClient() {}
// Called in response to a ScheduleMainFrame request made on the
// RemoteCompositorBridge.
// Note: The method should always be invoked asynchronously after the request
// is made.
virtual void BeginMainFrame() = 0;
};
} // namespace cc
#endif // CC_BLIMP_REMOTE_COMPOSITOR_BRIDGE_CLIENT_H_
// 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/test/fake_remote_compositor_bridge.h"
#include "base/bind.h"
#include "base/logging.h"
#include "cc/blimp/remote_compositor_bridge_client.h"
namespace cc {
FakeRemoteCompositorBridge::FakeRemoteCompositorBridge(
scoped_refptr<base::SingleThreadTaskRunner> compositor_main_task_runner)
: RemoteCompositorBridge(std::move(compositor_main_task_runner)),
client_(nullptr),
weak_factory_(this) {}
FakeRemoteCompositorBridge::~FakeRemoteCompositorBridge() {}
void FakeRemoteCompositorBridge::BindToClient(
RemoteCompositorBridgeClient* client) {
DCHECK(!client_);
client_ = client;
}
void FakeRemoteCompositorBridge::ScheduleMainFrame() {
compositor_main_task_runner_->PostTask(
FROM_HERE, base::Bind(&FakeRemoteCompositorBridge::BeginMainFrame,
weak_factory_.GetWeakPtr()));
}
void FakeRemoteCompositorBridge::BeginMainFrame() {
client_->BeginMainFrame();
}
} // namespace cc
// 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.
#ifndef CC_TEST_FAKE_REMOTE_COMPOSITOR_BRIDGE_H_
#define CC_TEST_FAKE_REMOTE_COMPOSITOR_BRIDGE_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "cc/blimp/compositor_proto_state.h"
#include "cc/blimp/remote_compositor_bridge.h"
namespace cc {
// An implementation of the RemoteCompositorBridge for tests that pump
// BeginMainFrames as soon as the client requests them.
class FakeRemoteCompositorBridge : public RemoteCompositorBridge {
public:
FakeRemoteCompositorBridge(
scoped_refptr<base::SingleThreadTaskRunner> compositor_main_task_runner);
~FakeRemoteCompositorBridge() override;
// RemoteCompositorBridge implementation.
void BindToClient(RemoteCompositorBridgeClient* client) override;
void ScheduleMainFrame() override;
void ProcessCompositorStateUpdate(
std::unique_ptr<CompositorProtoState> compositor_proto_state) override {}
private:
void BeginMainFrame();
RemoteCompositorBridgeClient* client_;
base::WeakPtrFactory<FakeRemoteCompositorBridge> weak_factory_;
};
} // namespace cc
#endif // CC_TEST_FAKE_REMOTE_COMPOSITOR_BRIDGE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment