cc: Glue LTHI and Scheduler changes for checker-imaging.
This change glues together the scheduling and tile management changes
for checker-imaging via ProxyImpl and SingleThreadProxy for enabling
checker-imaging. And adds integration LayerTreeTests, including a
scroll test to ensure that an impl-side pending tree does not affect
SyncedProperty state synchronization.
BUG=686267, 691041
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel
Review-Url: https://codereview.chromium.org/2717553005
Cr-Commit-Position: refs/heads/master@{#453508}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index e0d8f256..a966184 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -853,6 +853,7 @@
"trees/layer_tree_host_pixeltest_tiles.cc",
"trees/layer_tree_host_unittest.cc",
"trees/layer_tree_host_unittest_animation.cc",
+ "trees/layer_tree_host_unittest_checkerimaging.cc",
"trees/layer_tree_host_unittest_context.cc",
"trees/layer_tree_host_unittest_copyrequest.cc",
"trees/layer_tree_host_unittest_damage.cc",
diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc
index 9daa8f3..e53daf1 100644
--- a/cc/playback/raster_source.cc
+++ b/cc/playback/raster_source.cc
@@ -247,6 +247,8 @@
}
gfx::Rect RasterSource::GetRectForImage(ImageId image_id) const {
+ if (!display_list_)
+ return gfx::Rect();
return display_list_->GetRectForImage(image_id);
}
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index ae1991b..6dd7c39 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -526,7 +526,8 @@
// We must not finish the commit until the pending tree is free.
if (has_pending_tree_) {
- DCHECK(settings_.main_frame_before_activation_enabled);
+ DCHECK(settings_.main_frame_before_activation_enabled ||
+ current_pending_tree_is_impl_side_);
return false;
}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index e3dc1e1..bb90d2c 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -93,10 +93,12 @@
LayerTreeHostImplClient* host_impl_client,
TaskRunnerProvider* task_runner_provider,
TaskGraphRunner* task_graph_runner,
- RenderingStatsInstrumentation* stats_instrumentation) {
+ RenderingStatsInstrumentation* stats_instrumentation,
+ scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner) {
return base::WrapUnique(new LayerTreeHostImplForTesting(
test_hooks, settings, host_impl_client, task_runner_provider,
- task_graph_runner, stats_instrumentation));
+ task_graph_runner, stats_instrumentation,
+ std::move(image_worker_task_runner)));
}
protected:
@@ -106,7 +108,8 @@
LayerTreeHostImplClient* host_impl_client,
TaskRunnerProvider* task_runner_provider,
TaskGraphRunner* task_graph_runner,
- RenderingStatsInstrumentation* stats_instrumentation)
+ RenderingStatsInstrumentation* stats_instrumentation,
+ scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner)
: LayerTreeHostImpl(settings,
host_impl_client,
task_runner_provider,
@@ -114,10 +117,8 @@
task_graph_runner,
AnimationHost::CreateForTesting(ThreadInstance::IMPL),
0,
- nullptr),
- test_hooks_(test_hooks),
- block_notify_ready_to_activate_for_testing_(false),
- notify_ready_to_activate_was_blocked_(false) {}
+ std::move(image_worker_task_runner)),
+ test_hooks_(test_hooks) {}
void CreateResourceAndRasterBufferProvider(
std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
@@ -136,6 +137,11 @@
test_hooks_->DidFinishImplFrameOnThread(this);
}
+ void DidSendBeginMainFrame() override {
+ LayerTreeHostImpl::DidSendBeginMainFrame();
+ test_hooks_->DidSendBeginMainFrameOnThread(this);
+ }
+
void BeginMainFrameAborted(
CommitEarlyOutReason reason,
std::vector<std::unique_ptr<SwapPromise>> swap_promises) override {
@@ -208,6 +214,13 @@
}
}
+ void BlockImplSideInvalidationRequestsForTesting(bool block) override {
+ block_impl_side_invalidation_ = block;
+ if (!block_impl_side_invalidation_ && impl_side_invalidation_was_blocked_) {
+ RequestImplSideInvalidation();
+ }
+ }
+
void ActivateSyncTree() override {
test_hooks_->WillActivateTreeOnThread(this);
LayerTreeHostImpl::ActivateSyncTree();
@@ -250,14 +263,33 @@
test_hooks_->NotifyTileStateChangedOnThread(this, tile);
}
+ void InvalidateContentOnImplSide() override {
+ LayerTreeHostImpl::InvalidateContentOnImplSide();
+ test_hooks_->DidInvalidateContentOnImplSide(this);
+ }
+
+ void RequestImplSideInvalidation() override {
+ if (block_impl_side_invalidation_) {
+ impl_side_invalidation_was_blocked_ = true;
+ return;
+ }
+
+ impl_side_invalidation_was_blocked_ = false;
+ LayerTreeHostImpl::RequestImplSideInvalidation();
+ test_hooks_->DidRequestImplSideInvalidation(this);
+ }
+
AnimationHost* animation_host() const {
return static_cast<AnimationHost*>(mutator_host());
}
private:
TestHooks* test_hooks_;
- bool block_notify_ready_to_activate_for_testing_;
- bool notify_ready_to_activate_was_blocked_;
+ bool block_notify_ready_to_activate_for_testing_ = false;
+ bool notify_ready_to_activate_was_blocked_ = false;
+
+ bool block_impl_side_invalidation_ = false;
+ bool impl_side_invalidation_was_blocked_ = false;
};
// Implementation of LayerTreeHost callback interface.
@@ -342,12 +374,14 @@
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
MutatorHost* mutator_host) {
LayerTreeHost::InitParams params;
params.client = client;
params.task_graph_runner = task_graph_runner;
params.settings = &settings;
params.mutator_host = mutator_host;
+ params.image_worker_task_runner = std::move(image_worker_task_runner);
std::unique_ptr<LayerTreeHostForTesting> layer_tree_host(
new LayerTreeHostForTesting(test_hooks, ¶ms, mode));
@@ -377,7 +411,7 @@
LayerTreeHostImplForTesting::Create(
test_hooks_, GetSettings(), host_impl_client,
GetTaskRunnerProvider(), task_graph_runner(),
- rendering_stats_instrumentation());
+ rendering_stats_instrumentation(), image_worker_task_runner_);
input_handler_weak_ptr_ = host_impl->AsWeakPtr();
return host_impl;
}
@@ -595,7 +629,8 @@
layer_tree_host_ = LayerTreeHostForTesting::Create(
this, mode_, client_.get(), client_.get(), task_graph_runner_.get(),
- settings_, main_task_runner, impl_task_runner, animation_host_.get());
+ settings_, main_task_runner, impl_task_runner,
+ image_worker_->task_runner(), animation_host_.get());
ASSERT_TRUE(layer_tree_host_);
main_task_runner_ =
@@ -741,6 +776,9 @@
ASSERT_TRUE(impl_thread_->Start());
}
+ image_worker_ = base::MakeUnique<base::Thread>("ImageWorker");
+ ASSERT_TRUE(image_worker_->Start());
+
shared_bitmap_manager_.reset(new TestSharedBitmapManager);
gpu_memory_buffer_manager_.reset(new TestGpuMemoryBufferManager);
task_graph_runner_.reset(new TestTaskGraphRunner);
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 625f47b..3b1f5439 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -149,6 +149,10 @@
gfx::Vector2dF ScrollDelta(LayerImpl* layer_impl);
+ base::SingleThreadTaskRunner* image_worker_task_runner() const {
+ return image_worker_->task_runner().get();
+ }
+
private:
virtual void DispatchAddAnimationToPlayer(
AnimationPlayer* player_to_receive_animation,
@@ -186,6 +190,7 @@
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
std::unique_ptr<base::Thread> impl_thread_;
+ std::unique_ptr<base::Thread> image_worker_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
std::unique_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
std::unique_ptr<TestTaskGraphRunner> task_graph_runner_;
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h
index d54bbcc..3102137 100644
--- a/cc/test/test_hooks.h
+++ b/cc/test/test_hooks.h
@@ -28,6 +28,7 @@
virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
const BeginFrameArgs& args) {}
virtual void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) {}
+ virtual void DidSendBeginMainFrameOnThread(LayerTreeHostImpl* host_impl) {}
virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
CommitEarlyOutReason reason) {}
virtual void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) {}
@@ -58,6 +59,8 @@
bool has_unfinished_animation) {}
virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl,
base::TimeTicks monotonic_time) {}
+ virtual void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) {}
+ virtual void DidRequestImplSideInvalidation(LayerTreeHostImpl* host_impl) {}
// Asynchronous compositor thread hooks.
// These are called asynchronously from the LayerTreeHostImpl performing its
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 09eae2b..4ad7918 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -95,6 +95,7 @@
LayerTreeHost::LayerTreeHost(InitParams* params, CompositorMode mode)
: micro_benchmark_controller_(this),
+ image_worker_task_runner_(params->image_worker_task_runner),
compositor_mode_(mode),
ui_resource_manager_(base::MakeUnique<UIResourceManager>()),
client_(params->client),
@@ -104,9 +105,11 @@
id_(s_layer_tree_host_sequence_number.GetNext() + 1),
task_graph_runner_(params->task_graph_runner),
event_listener_properties_(),
- mutator_host_(params->mutator_host),
- image_worker_task_runner_(params->image_worker_task_runner) {
+ mutator_host_(params->mutator_host) {
DCHECK(task_graph_runner_);
+ DCHECK(!settings_.enable_checker_imaging || image_worker_task_runner_);
+ DCHECK(!settings_.enable_checker_imaging ||
+ settings_.image_decode_tasks_enabled);
mutator_host_->SetMutatorHostClient(this);
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 2b33aac..025336d 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -479,6 +479,8 @@
base::WeakPtr<InputHandler> input_handler_weak_ptr_;
+ scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner_;
+
private:
friend class LayerTreeHostSerializationTest;
@@ -599,8 +601,6 @@
MutatorHost* mutator_host_;
- scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner_;
-
DISALLOW_COPY_AND_ASSIGN(LayerTreeHost);
};
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index f99af61..fa252c5a0 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1212,6 +1212,11 @@
NOTREACHED();
}
+void LayerTreeHostImpl::BlockImplSideInvalidationRequestsForTesting(
+ bool block) {
+ NOTREACHED();
+}
+
void LayerTreeHostImpl::ResetTreesForTesting() {
if (active_tree_)
active_tree_->DetachLayers();
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 0787f7f4..4f62793 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -235,6 +235,7 @@
DISALLOW_COPY_AND_ASSIGN(FrameData);
};
+ virtual void DidSendBeginMainFrame() {}
virtual void BeginMainFrameAborted(
CommitEarlyOutReason reason,
std::vector<std::unique_ptr<SwapPromise>> swap_promises);
@@ -253,7 +254,8 @@
// Analogous to a commit, this function is used to create a sync tree and
// add impl-side invalidations to it.
- void InvalidateContentOnImplSide();
+ // virtual for testing.
+ virtual void InvalidateContentOnImplSide();
void SetTreeLayerFilterMutated(ElementId element_id,
LayerTreeImpl* tree,
@@ -318,6 +320,10 @@
// immediately if any notifications had been blocked while blocking.
virtual void BlockNotifyReadyToActivateForTesting(bool block);
+ // Prevents notifying the |client_| when an impl side invalidation request is
+ // made. When unblocked, the disabled request will immediately be called.
+ virtual void BlockImplSideInvalidationRequestsForTesting(bool block);
+
// Resets all of the trees to an empty state.
void ResetTreesForTesting();
diff --git a/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/cc/trees/layer_tree_host_unittest_checkerimaging.cc
new file mode 100644
index 0000000..580fa3e
--- /dev/null
+++ b/cc/trees/layer_tree_host_unittest_checkerimaging.cc
@@ -0,0 +1,196 @@
+// Copyright 2017 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/base/completion_event.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_external_begin_frame_source.h"
+#include "cc/test/fake_picture_layer.h"
+#include "cc/test/layer_tree_test.h"
+#include "cc/test/skia_common.h"
+#include "cc/test/test_compositor_frame_sink.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+namespace {
+
+class LayerTreeHostCheckerImagingTest : public LayerTreeTest {
+ public:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+ void AfterTest() override {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->image_decode_tasks_enabled = true;
+ settings->enable_checker_imaging = true;
+ }
+
+ void SetupTree() override {
+ // Set up a content client which creates the following tiling, x denoting
+ // the image to checker:
+ // |---|---|---|---|
+ // | x | x | | |
+ // |---|---|---|---|
+ // | x | x | | |
+ // |---|---|---|---|
+ gfx::Size layer_size(1000, 500);
+ content_layer_client_.set_bounds(layer_size);
+ content_layer_client_.set_fill_with_nonsolid_color(true);
+ sk_sp<SkImage> checkerable_image =
+ CreateDiscardableImage(gfx::Size(450, 450));
+ content_layer_client_.add_draw_image(checkerable_image, gfx::Point(0, 0),
+ PaintFlags());
+
+ layer_tree_host()->SetRootLayer(
+ FakePictureLayer::Create(&content_layer_client_));
+ layer_tree_host()->root_layer()->SetBounds(layer_size);
+ LayerTreeTest::SetupTree();
+ }
+
+ void FlushImageDecodeTasks() {
+ CompletionEvent completion_event;
+ image_worker_task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind([](CompletionEvent* event) { event->Signal(); },
+ base::Unretained(&completion_event)));
+ completion_event.Wait();
+ }
+
+ private:
+ // Accessed only on the main thread.
+ FakeContentLayerClient content_layer_client_;
+};
+
+class LayerTreeHostCheckerImagingTestMergeWithMainFrame
+ : public LayerTreeHostCheckerImagingTest {
+ void BeginMainFrame(const BeginFrameArgs& args) override {
+ if (layer_tree_host()->SourceFrameNumber() == 1) {
+ // The first commit has happened, invalidate a tile outside the region
+ // for the image to ensure that the final invalidation on the pending
+ // tree is the union of this and impl-side invalidation.
+ layer_tree_host()->root_layer()->SetNeedsDisplayRect(
+ gfx::Rect(600, 0, 50, 500));
+ layer_tree_host()->SetNeedsCommit();
+ }
+ }
+
+ void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_of_commits_ == 1) {
+ // Send the blocked invalidation request before notifying that we're ready
+ // to commit, since the invalidation will be merged with the commit.
+ host_impl->BlockImplSideInvalidationRequestsForTesting(false);
+ }
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (++num_of_commits_) {
+ case 1: {
+ // The first commit has happened. Run all tasks on the image worker to
+ // ensure that the decode completion triggers an impl-side invalidation
+ // request.
+ FlushImageDecodeTasks();
+
+ // Block notifying the scheduler of this request until we get a commit.
+ host_impl->BlockImplSideInvalidationRequestsForTesting(true);
+ host_impl->SetNeedsCommit();
+ } break;
+ case 2: {
+ // Ensure that the expected tiles are invalidated on the sync tree.
+ PictureLayerImpl* sync_layer_impl = static_cast<PictureLayerImpl*>(
+ host_impl->sync_tree()->root_layer_for_testing());
+ PictureLayerTiling* sync_tiling =
+ sync_layer_impl->picture_layer_tiling_set()
+ ->FindTilingWithResolution(TileResolution::HIGH_RESOLUTION);
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 2; j++) {
+ Tile* tile =
+ sync_tiling->TileAt(i, j) ? sync_tiling->TileAt(i, j) : nullptr;
+
+ // If this is the pending tree, then only the invalidated tiles
+ // exist and have a raster task. If its the active tree, then only
+ // the invalidated tiles have a raster task.
+ if (i < 3) {
+ EXPECT_TRUE(tile->HasRasterTask());
+ } else if (host_impl->pending_tree()) {
+ EXPECT_EQ(tile, nullptr);
+ } else {
+ EXPECT_FALSE(tile->HasRasterTask());
+ }
+ }
+ }
+ EndTest();
+ } break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void AfterTest() override { EXPECT_EQ(num_of_commits_, 2); }
+
+ int num_of_commits_ = 0;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostCheckerImagingTestMergeWithMainFrame);
+
+class LayerTreeHostCheckerImagingTestImplSideTree
+ : public LayerTreeHostCheckerImagingTest {
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ ++num_of_impl_side_invalidations_;
+
+ // The source_frame_number of the sync tree should be from the first main
+ // frame, since this is an impl-side sync tree.
+ EXPECT_EQ(host_impl->sync_tree()->source_frame_number(), 0);
+
+ // Ensure that the expected tiles are invalidated on the sync tree.
+ PictureLayerImpl* sync_layer_impl = static_cast<PictureLayerImpl*>(
+ host_impl->sync_tree()->root_layer_for_testing());
+ PictureLayerTiling* sync_tiling =
+ sync_layer_impl->picture_layer_tiling_set()->FindTilingWithResolution(
+ TileResolution::HIGH_RESOLUTION);
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 2; j++) {
+ Tile* tile =
+ sync_tiling->TileAt(i, j) ? sync_tiling->TileAt(i, j) : nullptr;
+
+ // If this is the pending tree, then only the invalidated tiles
+ // exist and have a raster task. If its the active tree, then only
+ // the invalidated tiles have a raster task.
+ if (i < 2) {
+ EXPECT_TRUE(tile->HasRasterTask());
+ } else if (host_impl->pending_tree()) {
+ EXPECT_EQ(tile, nullptr);
+ } else {
+ EXPECT_FALSE(tile->HasRasterTask());
+ }
+ }
+ }
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ num_of_commits_++;
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ num_of_activations_++;
+ if (num_of_activations_ == 2)
+ EndTest();
+ }
+
+ void AfterTest() override {
+ EXPECT_EQ(num_of_activations_, 2);
+ EXPECT_EQ(num_of_commits_, 1);
+ EXPECT_EQ(num_of_impl_side_invalidations_, 1);
+ }
+
+ int num_of_activations_ = 0;
+ int num_of_commits_ = 0;
+ int num_of_impl_side_invalidations_ = 0;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCheckerImagingTestImplSideTree);
+
+} // namespace
+} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 9f545a5..151eb26 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -10,6 +10,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
+#include "cc/base/completion_event.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/scroll_elasticity_helper.h"
#include "cc/layers/layer.h"
@@ -2070,5 +2071,175 @@
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostScrollTestPropertyTreeUpdate);
+class LayerTreeHostScrollTestImplSideInvalidation
+ : public LayerTreeHostScrollTest {
+ void BeginTest() override {
+ layer_tree_host()->outer_viewport_scroll_layer()->set_did_scroll_callback(
+ base::Bind(&LayerTreeHostScrollTestImplSideInvalidation::
+ DidScrollOuterViewport,
+ base::Unretained(this)));
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DidScrollOuterViewport(const gfx::ScrollOffset& offset) {
+ // Defer responding to the main frame until an impl-side pending tree is
+ // created for the invalidation request.
+ {
+ CompletionEvent completion;
+ task_runner_provider()->ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostScrollTestImplSideInvalidation::
+ WaitForInvalidationOnImplThread,
+ base::Unretained(this), &completion));
+ completion.Wait();
+ }
+
+ switch (++num_of_deltas_) {
+ case 1: {
+ // First set of deltas is here. The impl thread will scroll to the
+ // second case on activation, so add a delta from the main thread that
+ // takes us to the final value.
+ Layer* outer_viewport_layer =
+ layer_tree_host()->outer_viewport_scroll_layer();
+ gfx::ScrollOffset delta_to_send =
+ outer_viewport_offsets_[2] - outer_viewport_offsets_[1];
+ outer_viewport_layer->SetScrollOffset(
+ outer_viewport_layer->scroll_offset() + delta_to_send);
+ } break;
+ case 2:
+ // Let the commit abort for the second set of deltas.
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void WaitForInvalidationOnImplThread(CompletionEvent* completion) {
+ impl_side_invalidation_event_ = completion;
+ SignalCompletionIfPossible();
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ invalidated_on_impl_thread_ = true;
+ SignalCompletionIfPossible();
+ }
+
+ void SignalCompletionIfPossible() {
+ if (!invalidated_on_impl_thread_ || !impl_side_invalidation_event_)
+ return;
+
+ impl_side_invalidation_event_->Signal();
+ impl_side_invalidation_event_ = nullptr;
+ invalidated_on_impl_thread_ = false;
+ }
+
+ void DidSendBeginMainFrameOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (++num_of_main_frames_) {
+ case 1:
+ // Do nothing for the first BeginMainFrame.
+ break;
+ case 2:
+ // Add some more delta to the active tree state of the scroll offset and
+ // a commit to send this additional delta to the main thread.
+ host_impl->active_tree()
+ ->OuterViewportScrollLayer()
+ ->SetCurrentScrollOffset(outer_viewport_offsets_[1]);
+ host_impl->SetNeedsCommit();
+
+ // Request an impl-side invalidation to create an impl-side pending
+ // tree.
+ host_impl->RequestImplSideInvalidation();
+ break;
+ case 3:
+ // Request another impl-side invalidation so the aborted commit comes
+ // after this tree is activated.
+ host_impl->RequestImplSideInvalidation();
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
+ CommitEarlyOutReason reason) override {
+ // The aborted main frame is bound to come after the fourth activation,
+ // since the activation should occur synchronously after the impl-side
+ // invalidation, and the main thread is released after this activation. It
+ // should leave the scroll offset unchanged.
+ EXPECT_EQ(reason, CommitEarlyOutReason::FINISHED_NO_UPDATES);
+ EXPECT_EQ(num_of_activations_, 4);
+ EXPECT_EQ(num_of_main_frames_, 3);
+ EXPECT_EQ(host_impl->active_tree()
+ ->OuterViewportScrollLayer()
+ ->CurrentScrollOffset(),
+ outer_viewport_offsets_[2]);
+ EndTest();
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (++num_of_activations_) {
+ case 1:
+ // Now that we have the active tree, scroll a layer and ask for a commit
+ // to send a BeginMainFrame with the scroll delta to the main thread.
+ host_impl->active_tree()
+ ->OuterViewportScrollLayer()
+ ->SetCurrentScrollOffset(outer_viewport_offsets_[0]);
+ host_impl->SetNeedsCommit();
+ break;
+ case 2:
+ // The second activation is from an impl-side pending tree so the source
+ // frame number on the active tree remains unchanged, and the scroll
+ // offset on the active tree should also remain unchanged.
+ EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 0);
+ EXPECT_EQ(host_impl->active_tree()
+ ->OuterViewportScrollLayer()
+ ->CurrentScrollOffset(),
+ outer_viewport_offsets_[1]);
+ break;
+ case 3:
+ // The third activation is from a commit. The scroll offset on the
+ // active tree should include deltas sent from the main thread.
+ EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
+ EXPECT_EQ(host_impl->active_tree()
+ ->OuterViewportScrollLayer()
+ ->CurrentScrollOffset(),
+ outer_viewport_offsets_[2]);
+ break;
+ case 4:
+ // The fourth activation is from an impl-side pending tree, which should
+ // leave the scroll offset unchanged.
+ EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
+ EXPECT_EQ(host_impl->active_tree()
+ ->OuterViewportScrollLayer()
+ ->CurrentScrollOffset(),
+ outer_viewport_offsets_[2]);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void AfterTest() override {
+ EXPECT_EQ(num_of_activations_, 4);
+ EXPECT_EQ(num_of_deltas_, 2);
+ EXPECT_EQ(num_of_main_frames_, 3);
+ }
+
+ const gfx::ScrollOffset outer_viewport_offsets_[3] = {
+ gfx::ScrollOffset(20, 20), gfx::ScrollOffset(50, 50),
+ gfx::ScrollOffset(70, 70)};
+
+ // Impl thread.
+ int num_of_activations_ = 0;
+ int num_of_main_frames_ = 0;
+ bool invalidated_on_impl_thread_ = false;
+ CompletionEvent* impl_side_invalidation_event_ = nullptr;
+
+ // Main thread.
+ int num_of_deltas_ = 0;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostScrollTestImplSideInvalidation);
+
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index b25a3cd8..d0083b3 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -82,7 +82,11 @@
size_t scheduled_raster_task_limit = 32;
bool use_occlusion_for_tile_prioritization = false;
bool verify_clip_tree_calculations = false;
+
+ // TODO(khushalsagar): Enable for all client and remove this flag if possible.
+ // See crbug/com/696864.
bool image_decode_tasks_enabled = false;
+
bool use_layer_lists = false;
int max_staging_buffer_usage_in_bytes = 32 * 1024 * 1024;
ManagedMemoryPolicy gpu_memory_policy;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 7c2cb9fb2..5691956 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -434,9 +434,7 @@
void ProxyImpl::NeedsImplSideInvalidation() {
DCHECK(IsImplThread());
- // TODO(khushalsagar): Plumb this to the scheduler when
- // https://codereview.chromium.org/2659123004/ lands. See crbug.com/686267.
- NOTIMPLEMENTED();
+ scheduler_->SetNeedsImplSideInvalidation();
}
void ProxyImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
@@ -467,6 +465,7 @@
MainThreadTaskRunner()->PostTask(
FROM_HERE, base::Bind(&ProxyMain::BeginMainFrame, proxy_main_weak_ptr_,
base::Passed(&begin_main_frame_state)));
+ layer_tree_host_impl_->DidSendBeginMainFrame();
devtools_instrumentation::DidRequestMainThreadFrame(layer_tree_host_id_);
}
@@ -556,7 +555,9 @@
}
void ProxyImpl::ScheduledActionPerformImplSideInvalidation() {
- NOTIMPLEMENTED();
+ TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionPerformImplSideInvalidation");
+ DCHECK(IsImplThread());
+ layer_tree_host_impl_->InvalidateContentOnImplSide();
}
void ProxyImpl::SendBeginMainFrameNotExpectedSoon() {
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 7469f7cd..33ed54a 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -63,6 +63,9 @@
DebugScopedSetImplThread impl(task_runner_provider_);
const LayerTreeSettings& settings = layer_tree_host_->GetSettings();
+ DCHECK(settings.single_thread_proxy_scheduler ||
+ !settings.enable_checker_imaging)
+ << "Checker-imaging is not supported in synchronous single threaded mode";
if (settings.single_thread_proxy_scheduler && !scheduler_on_impl_thread_) {
SchedulerSettings scheduler_settings(settings.ToSchedulerSettings());
scheduler_settings.commit_to_active_tree = CommitToActiveTree();
@@ -425,9 +428,8 @@
}
void SingleThreadProxy::NeedsImplSideInvalidation() {
- // TODO(khushalsagar): Plumb this to the scheduler when
- // https://codereview.chromium.org/2659123004/ lands. See crbug.com/686267.
- NOTIMPLEMENTED();
+ DCHECK(scheduler_on_impl_thread_);
+ scheduler_on_impl_thread_->SetNeedsImplSideInvalidation();
}
void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
@@ -604,6 +606,7 @@
task_runner_provider_->MainThreadTaskRunner()->PostTask(
FROM_HERE, base::Bind(&SingleThreadProxy::BeginMainFrame,
weak_factory_.GetWeakPtr(), begin_frame_args));
+ layer_tree_host_impl_->DidSendBeginMainFrame();
}
void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
@@ -732,7 +735,19 @@
}
void SingleThreadProxy::ScheduledActionPerformImplSideInvalidation() {
- NOTIMPLEMENTED();
+ DCHECK(scheduler_on_impl_thread_);
+
+ DebugScopedSetImplThread impl(task_runner_provider_);
+ commit_blocking_task_runner_.reset(new BlockingTaskRunner::CapturePostTasks(
+ task_runner_provider_->blocking_main_thread_task_runner()));
+ layer_tree_host_impl_->InvalidateContentOnImplSide();
+
+ // Invalidations go directly to the active tree, so we synchronously call
+ // NotifyReadyToActivate to update the scheduler and LTHI state correctly.
+ // Since in single-threaded mode the scheduler will wait for a ready to draw
+ // signal from LTHI, the draw will remain blocked till the invalidated tiles
+ // are ready.
+ NotifyReadyToActivate();
}
void SingleThreadProxy::UpdateBrowserControlsState(