diff options
author | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-26 10:06:05 +0000 |
---|---|---|
committer | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-26 10:06:05 +0000 |
commit | 3dc0c77486b217a40c817e4942a11dfd48651533 (patch) | |
tree | 6c12d3d3f59cb6bf8e5ec841307b32c1c826d444 | |
parent | b5556b29fb292017f98224b4dc8894bd16bc7272 (diff) | |
download | chromium_src-3dc0c77486b217a40c817e4942a11dfd48651533.zip chromium_src-3dc0c77486b217a40c817e4942a11dfd48651533.tar.gz chromium_src-3dc0c77486b217a40c817e4942a11dfd48651533.tar.bz2 |
cc: Move scheduling logic out of OutputSurface
This moves the vsync throttling enabled/disabled
logic and the synthetic/emulated BeginFrame logic
out of OutputSurface and moves it to the Scheduler.
This then allows us to also remove the retroactive
BeginFrame logic from OutputSurface since the
Scheduler also has retroactive BeginFrame logic.
BUG=246861
BUG=251909
Review URL: https://codereview.chromium.org/221833009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266348 0039d316-1c4b-4281-b951-d872f2087c98
33 files changed, 577 insertions, 724 deletions
@@ -424,8 +424,6 @@ 'scheduler/delay_based_time_source.cc', 'scheduler/delay_based_time_source.h', 'scheduler/draw_swap_readback_result.h', - 'scheduler/frame_rate_controller.cc', - 'scheduler/frame_rate_controller.h', 'scheduler/scheduler.cc', 'scheduler/scheduler.h', 'scheduler/scheduler_settings.cc', diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 83233cc..f9688b5 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -83,7 +83,6 @@ 'resources/tile_priority_unittest.cc', 'resources/video_resource_updater_unittest.cc', 'scheduler/delay_based_time_source_unittest.cc', - 'scheduler/frame_rate_controller_unittest.cc', 'scheduler/scheduler_state_machine_unittest.cc', 'scheduler/scheduler_unittest.cc', 'test/layer_tree_json_parser_unittest.cc', diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc index 436e37c..0f68b5b 100644 --- a/cc/output/output_surface.cc +++ b/cc/output/output_surface.cc @@ -44,66 +44,32 @@ const double kGpuLatencyEstimationPercentile = 100.0; namespace cc { OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider) - : context_provider_(context_provider), + : client_(NULL), + context_provider_(context_provider), device_scale_factor_(-1), - begin_frame_interval_(BeginFrameArgs::DefaultInterval()), - throttle_frame_production_(true), - needs_begin_frame_(false), - client_ready_for_begin_frame_(true), - client_(NULL), - check_for_retroactive_begin_frame_pending_(false), external_stencil_test_enabled_(false), weak_ptr_factory_(this), - gpu_latency_history_(kGpuLatencyHistorySize) {} + gpu_latency_history_(kGpuLatencyHistorySize) { +} OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) - : software_device_(software_device.Pass()), + : client_(NULL), + software_device_(software_device.Pass()), device_scale_factor_(-1), - begin_frame_interval_(BeginFrameArgs::DefaultInterval()), - throttle_frame_production_(true), - needs_begin_frame_(false), - client_ready_for_begin_frame_(true), - client_(NULL), - check_for_retroactive_begin_frame_pending_(false), external_stencil_test_enabled_(false), weak_ptr_factory_(this), - gpu_latency_history_(kGpuLatencyHistorySize) {} + gpu_latency_history_(kGpuLatencyHistorySize) { +} OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider, scoped_ptr<SoftwareOutputDevice> software_device) - : context_provider_(context_provider), + : client_(NULL), + context_provider_(context_provider), software_device_(software_device.Pass()), device_scale_factor_(-1), - begin_frame_interval_(BeginFrameArgs::DefaultInterval()), - throttle_frame_production_(true), - needs_begin_frame_(false), - client_ready_for_begin_frame_(true), - client_(NULL), - check_for_retroactive_begin_frame_pending_(false), external_stencil_test_enabled_(false), weak_ptr_factory_(this), - gpu_latency_history_(kGpuLatencyHistorySize) {} - -void OutputSurface::SetThrottleFrameProduction(bool enable) { - DCHECK(!frame_rate_controller_); - throttle_frame_production_ = enable; -} - -void OutputSurface::InitializeBeginFrameEmulation( - base::SingleThreadTaskRunner* task_runner, - base::TimeDelta interval) { - DCHECK(throttle_frame_production_); - scoped_refptr<DelayBasedTimeSource> time_source; - if (gfx::FrameTime::TimestampsAreHighRes()) - time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner); - else - time_source = DelayBasedTimeSource::Create(interval, task_runner); - frame_rate_controller_.reset(new FrameRateController(time_source)); - - frame_rate_controller_->SetClient(this); - frame_rate_controller_->SetDeadlineAdjustment( - capabilities_.adjust_deadline_for_parent ? - BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta()); + gpu_latency_history_(kGpuLatencyHistorySize) { } void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase, @@ -114,14 +80,7 @@ void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase, (timebase - base::TimeTicks()).InSecondsF(), "interval", interval.InSecondsF()); - begin_frame_interval_ = interval; - if (frame_rate_controller_) - frame_rate_controller_->SetTimebaseAndInterval(timebase, interval); -} - -void OutputSurface::FrameRateControllerTick(const BeginFrameArgs& args) { - DCHECK(frame_rate_controller_); - BeginFrame(args); + client_->CommitVSyncParameters(timebase, interval); } // Forwarded to OutputSurfaceClient @@ -130,92 +89,12 @@ void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { client_->SetNeedsRedrawRect(damage_rect); } -void OutputSurface::SetNeedsBeginFrame(bool enable) { - TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable); - needs_begin_frame_ = enable; - client_ready_for_begin_frame_ = true; - if (!throttle_frame_production_) { - if (enable) { - base::TimeTicks frame_time = gfx::FrameTime::Now(); - base::TimeTicks deadline = frame_time + begin_frame_interval_; - skipped_begin_frame_args_ = - BeginFrameArgs::Create(frame_time, deadline, begin_frame_interval_); - } - } else if (frame_rate_controller_) { - BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable); - if (skipped.IsValid()) - skipped_begin_frame_args_ = skipped; - } - - if (needs_begin_frame_) - PostCheckForRetroactiveBeginFrame(); -} - -void OutputSurface::BeginFrame(const BeginFrameArgs& args) { - TRACE_EVENT1("cc", - "OutputSurface::BeginFrame", - "client_ready_for_begin_frame_", - client_ready_for_begin_frame_); - if (!needs_begin_frame_ || !client_ready_for_begin_frame_) { - skipped_begin_frame_args_ = args; - } else { - client_ready_for_begin_frame_ = false; - client_->BeginFrame(args); - // args might be an alias for skipped_begin_frame_args_. - // Do not reset it before calling BeginFrame! - skipped_begin_frame_args_ = BeginFrameArgs(); - } -} - -base::TimeTicks OutputSurface::RetroactiveBeginFrameDeadline() { - // TODO(brianderson): Remove the alternative deadline once we have better - // deadline estimations. - base::TimeTicks alternative_deadline = - skipped_begin_frame_args_.frame_time + - BeginFrameArgs::DefaultRetroactiveBeginFramePeriod(); - return std::max(skipped_begin_frame_args_.deadline, alternative_deadline); -} - -void OutputSurface::PostCheckForRetroactiveBeginFrame() { - if (!skipped_begin_frame_args_.IsValid() || - check_for_retroactive_begin_frame_pending_) - return; - - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&OutputSurface::CheckForRetroactiveBeginFrame, - weak_ptr_factory_.GetWeakPtr())); - check_for_retroactive_begin_frame_pending_ = true; -} - -void OutputSurface::CheckForRetroactiveBeginFrame() { - TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginFrame"); - check_for_retroactive_begin_frame_pending_ = false; - if (!throttle_frame_production_ || - gfx::FrameTime::Now() < RetroactiveBeginFrameDeadline()) - BeginFrame(skipped_begin_frame_args_); -} - -void OutputSurface::DidSwapBuffers() { - TRACE_EVENT0("cc", "OutputSurface::DidSwapBuffers"); - client_->DidSwapBuffers(); -} - -void OutputSurface::OnSwapBuffersComplete() { - TRACE_EVENT0("cc", "OutputSurface::OnSwapBuffersComplete"); - client_->DidSwapBuffersComplete(); -} - void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { client_->ReclaimResources(ack); } void OutputSurface::DidLoseOutputSurface() { TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); - client_ready_for_begin_frame_ = true; - skipped_begin_frame_args_ = BeginFrameArgs(); - if (frame_rate_controller_) - frame_rate_controller_->SetActive(false); pending_gpu_latency_query_ids_.clear(); available_gpu_latency_query_ids_.clear(); client_->DidLoseOutputSurface(); @@ -234,8 +113,6 @@ void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform, } OutputSurface::~OutputSurface() { - if (frame_rate_controller_) - frame_rate_controller_->SetActive(false); ResetContext3d(); } @@ -364,7 +241,7 @@ void OutputSurface::BindFramebuffer() { void OutputSurface::SwapBuffers(CompositorFrame* frame) { if (frame->software_frame_data) { PostSwapBuffersComplete(); - DidSwapBuffers(); + client_->DidSwapBuffers(); return; } @@ -380,7 +257,7 @@ void OutputSurface::SwapBuffers(CompositorFrame* frame) { frame->gl_frame_data->sub_buffer_rect); } - DidSwapBuffers(); + client_->DidSwapBuffers(); } base::TimeDelta OutputSurface::GpuLatencyEstimate() { @@ -463,6 +340,12 @@ void OutputSurface::PostSwapBuffersComplete() { weak_ptr_factory_.GetWeakPtr())); } +// We don't post tasks bound to the client directly since they might run +// after the OutputSurface has been destroyed. +void OutputSurface::OnSwapBuffersComplete() { + client_->DidSwapBuffersComplete(); +} + void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy", "bytes_limit_when_visible", policy.bytes_limit_when_visible); diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index 2645d84..c82a087 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h @@ -13,10 +13,10 @@ #include "base/memory/weak_ptr.h" #include "cc/base/cc_export.h" #include "cc/base/rolling_time_delta_history.h" +#include "cc/output/begin_frame_args.h" #include "cc/output/context_provider.h" #include "cc/output/overlay_candidate_validator.h" #include "cc/output/software_output_device.h" -#include "cc/scheduler/frame_rate_controller.h" namespace base { class SingleThreadTaskRunner; } @@ -42,7 +42,7 @@ class OutputSurfaceClient; // From here on, it will only be used on the compositor thread. // 3. If the 3D context is lost, then the compositor will delete the output // surface (on the compositor thread) and go back to step 1. -class CC_EXPORT OutputSurface : public FrameRateControllerClient { +class CC_EXPORT OutputSurface { public: enum { DEFAULT_MAX_FRAMES_PENDING = 2 @@ -108,9 +108,6 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { // Enable or disable vsync. void SetThrottleFrameProduction(bool enable); - void InitializeBeginFrameEmulation(base::SingleThreadTaskRunner* task_runner, - base::TimeDelta interval); - virtual void EnsureBackbuffer(); virtual void DiscardBackbuffer(); @@ -131,7 +128,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { // Requests a BeginFrame notification from the output surface. The // notification will be delivered by calling // OutputSurfaceClient::BeginFrame until the callback is disabled. - virtual void SetNeedsBeginFrame(bool enable); + virtual void SetNeedsBeginFrame(bool enable) {} bool HasClient() { return !!client_; } @@ -145,6 +142,8 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { } protected: + OutputSurfaceClient* client_; + // Synchronously initialize context3d and enter hardware mode. // This can only supported in threaded compositing mode. bool InitializeAndSetContext3d( @@ -159,29 +158,11 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_; gfx::Size surface_size_; float device_scale_factor_; - base::TimeDelta begin_frame_interval_; - // The FrameRateController is deprecated. - // Platforms should move to native BeginFrames instead. void CommitVSyncParameters(base::TimeTicks timebase, base::TimeDelta interval); - virtual void FrameRateControllerTick(const BeginFrameArgs& args) OVERRIDE; - scoped_ptr<FrameRateController> frame_rate_controller_; - - bool throttle_frame_production_; - bool needs_begin_frame_; - bool client_ready_for_begin_frame_; - - // This stores a BeginFrame that we couldn't process immediately, - // but might process retroactively in the near future. - BeginFrameArgs skipped_begin_frame_args_; - // Forwarded to OutputSurfaceClient but threaded through OutputSurface - // first so OutputSurface has a chance to update the FrameRateController void SetNeedsRedrawRect(const gfx::Rect& damage_rect); - void BeginFrame(const BeginFrameArgs& args); - void DidSwapBuffers(); - void OnSwapBuffersComplete(); void ReclaimResources(const CompositorFrameAck* ack); void DidLoseOutputSurface(); void SetExternalStencilTest(bool enabled); @@ -190,22 +171,13 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { const gfx::Rect& clip, bool valid_for_tile_management); - // virtual for testing. - virtual base::TimeTicks RetroactiveBeginFrameDeadline(); - virtual void PostCheckForRetroactiveBeginFrame(); - void CheckForRetroactiveBeginFrame(); - private: - OutputSurfaceClient* client_; - void SetUpContext3d(); void ResetContext3d(); void SetMemoryPolicy(const ManagedMemoryPolicy& policy); void UpdateAndMeasureGpuLatency(); - // check_for_retroactive_begin_frame_pending_ is used to avoid posting - // redundant checks for a retroactive BeginFrame. - bool check_for_retroactive_begin_frame_pending_; + void OnSwapBuffersComplete(); bool external_stencil_test_enabled_; diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h index 3b92e27..c188fe0 100644 --- a/cc/output/output_surface_client.h +++ b/cc/output/output_surface_client.h @@ -29,6 +29,8 @@ class CC_EXPORT OutputSurfaceClient { // committed. virtual void DeferredInitialize() = 0; virtual void ReleaseGL() = 0; + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) = 0; virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0; virtual void BeginFrame(const BeginFrameArgs& args) = 0; virtual void DidSwapBuffers() = 0; diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc index 9e7724f..05381fc 100644 --- a/cc/output/output_surface_unittest.cc +++ b/cc/output/output_surface_unittest.cc @@ -23,20 +23,14 @@ namespace { class TestOutputSurface : public OutputSurface { public: explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider) - : OutputSurface(context_provider), - retroactive_begin_frame_deadline_enabled_(false), - override_retroactive_period_(false) {} + : OutputSurface(context_provider) {} explicit TestOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) - : OutputSurface(software_device.Pass()), - retroactive_begin_frame_deadline_enabled_(false), - override_retroactive_period_(false) {} + : OutputSurface(software_device.Pass()) {} TestOutputSurface(scoped_refptr<ContextProvider> context_provider, scoped_ptr<SoftwareOutputDevice> software_device) - : OutputSurface(context_provider, software_device.Pass()), - retroactive_begin_frame_deadline_enabled_(false), - override_retroactive_period_(false) {} + : OutputSurface(context_provider, software_device.Pass()) {} bool InitializeNewContext3d( scoped_refptr<ContextProvider> new_context_provider) { @@ -51,46 +45,14 @@ class TestOutputSurface : public OutputSurface { } void BeginFrameForTesting() { - OutputSurface::BeginFrame(BeginFrameArgs::CreateExpiredForTesting()); + client_->BeginFrame(BeginFrameArgs::CreateExpiredForTesting()); } - void DidSwapBuffersForTesting() { - DidSwapBuffers(); - } - - void OnSwapBuffersCompleteForTesting() { - OnSwapBuffersComplete(); - } + void DidSwapBuffersForTesting() { client_->DidSwapBuffers(); } - void EnableRetroactiveBeginFrameDeadline(bool enable, - bool override_retroactive_period, - base::TimeDelta period_override) { - retroactive_begin_frame_deadline_enabled_ = enable; - override_retroactive_period_ = override_retroactive_period; - retroactive_period_override_ = period_override; - } + void OnSwapBuffersCompleteForTesting() { client_->DidSwapBuffersComplete(); } protected: - virtual void PostCheckForRetroactiveBeginFrame() OVERRIDE { - // For testing purposes, we check immediately rather than posting a task. - CheckForRetroactiveBeginFrame(); - } - - virtual base::TimeTicks RetroactiveBeginFrameDeadline() OVERRIDE { - if (retroactive_begin_frame_deadline_enabled_) { - if (override_retroactive_period_) { - return skipped_begin_frame_args_.frame_time + - retroactive_period_override_; - } else { - return OutputSurface::RetroactiveBeginFrameDeadline(); - } - } - return base::TimeTicks(); - } - - bool retroactive_begin_frame_deadline_enabled_; - bool override_retroactive_period_; - base::TimeDelta retroactive_period_override_; }; class TestSoftwareOutputDevice : public SoftwareOutputDevice { @@ -209,152 +171,6 @@ TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) { InitializeNewContextExpectFail(); } -TEST(OutputSurfaceTest, BeginFrameEmulation) { - TestOutputSurface output_surface(TestContextProvider::Create()); - EXPECT_FALSE(output_surface.HasClient()); - - FakeOutputSurfaceClient client; - EXPECT_TRUE(output_surface.BindToClient(&client)); - EXPECT_TRUE(output_surface.HasClient()); - EXPECT_FALSE(client.deferred_initialize_called()); - - // Initialize BeginFrame emulation - scoped_refptr<base::TestSimpleTaskRunner> task_runner = - new base::TestSimpleTaskRunner; - const base::TimeDelta display_refresh_interval = - BeginFrameArgs::DefaultInterval(); - - output_surface.InitializeBeginFrameEmulation(task_runner.get(), - display_refresh_interval); - - output_surface.EnableRetroactiveBeginFrameDeadline( - false, false, base::TimeDelta()); - - // We should start off with 0 BeginFrames - EXPECT_EQ(client.begin_frame_count(), 0); - - // We should not have a pending task until a BeginFrame has been - // requested. - EXPECT_FALSE(task_runner->HasPendingTask()); - output_surface.SetNeedsBeginFrame(true); - EXPECT_TRUE(task_runner->HasPendingTask()); - - // BeginFrame should be called on the first tick. - task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 1); - - // BeginFrame should not be called when there is a pending BeginFrame. - task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 1); - // SetNeedsBeginFrame should clear the pending BeginFrame after - // a SwapBuffers. - output_surface.DidSwapBuffersForTesting(); - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 1); - task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 2); - - // Calling SetNeedsBeginFrame again indicates a swap did not occur but - // the client still wants another BeginFrame. - output_surface.SetNeedsBeginFrame(true); - task_runner->RunPendingTasks(); - EXPECT_EQ(client.begin_frame_count(), 3); - - // Disabling SetNeedsBeginFrame should prevent further BeginFrames. - output_surface.SetNeedsBeginFrame(false); - task_runner->RunPendingTasks(); - EXPECT_FALSE(task_runner->HasPendingTask()); - EXPECT_EQ(client.begin_frame_count(), 3); -} - -TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginFrames) { - TestOutputSurface output_surface(TestContextProvider::Create()); - EXPECT_FALSE(output_surface.HasClient()); - - FakeOutputSurfaceClient client; - EXPECT_TRUE(output_surface.BindToClient(&client)); - EXPECT_TRUE(output_surface.HasClient()); - EXPECT_FALSE(client.deferred_initialize_called()); - - output_surface.EnableRetroactiveBeginFrameDeadline( - true, false, base::TimeDelta()); - - // Optimistically injected BeginFrames should be throttled if - // SetNeedsBeginFrame is false... - output_surface.SetNeedsBeginFrame(false); - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 0); - // ...and retroactively triggered by a SetNeedsBeginFrame. - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 1); - - // Optimistically injected BeginFrames should be throttled by pending - // BeginFrames... - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 1); - // ...and retroactively triggered by a SetNeedsBeginFrame. - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 2); - // ...or retroactively triggered by a Swap. - output_surface.BeginFrameForTesting(); - EXPECT_EQ(client.begin_frame_count(), 2); - output_surface.DidSwapBuffersForTesting(); - output_surface.SetNeedsBeginFrame(true); - EXPECT_EQ(client.begin_frame_count(), 3); -} - -TEST(OutputSurfaceTest, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating) { - scoped_refptr<TestContextProvider> context_provider = - TestContextProvider::Create(); - - TestOutputSurface output_surface(context_provider); - EXPECT_FALSE(output_surface.HasClient()); - - FakeOutputSurfaceClient client; - EXPECT_TRUE(output_surface.BindToClient(&client)); - EXPECT_TRUE(output_surface.HasClient()); - EXPECT_FALSE(client.deferred_initialize_called()); - - base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10); - - // Initialize BeginFrame emulation - scoped_refptr<base::TestSimpleTaskRunner> task_runner = - new base::TestSimpleTaskRunner; - const base::TimeDelta display_refresh_interval = big_interval; - - output_surface.InitializeBeginFrameEmulation(task_runner.get(), - display_refresh_interval); - - // We need to subtract an epsilon from Now() because some platforms have - // a slow clock. - output_surface.CommitVSyncParametersForTesting( - gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval); - - output_surface.EnableRetroactiveBeginFrameDeadline(true, true, big_interval); - - // We should start off with 0 BeginFrames - EXPECT_EQ(client.begin_frame_count(), 0); - - // The first SetNeedsBeginFrame(true) should start a retroactive - // BeginFrame. - EXPECT_FALSE(task_runner->HasPendingTask()); - output_surface.SetNeedsBeginFrame(true); - EXPECT_TRUE(task_runner->HasPendingTask()); - EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2); - EXPECT_EQ(client.begin_frame_count(), 1); - - output_surface.SetNeedsBeginFrame(false); - EXPECT_TRUE(task_runner->HasPendingTask()); - EXPECT_EQ(client.begin_frame_count(), 1); - - // The second SetNeedBeginFrame(true) should not retroactively start a - // BeginFrame if the timestamp would be the same as the previous - // BeginFrame. - output_surface.SetNeedsBeginFrame(true); - EXPECT_TRUE(task_runner->HasPendingTask()); - EXPECT_EQ(client.begin_frame_count(), 1); -} - TEST(OutputSurfaceTest, MemoryAllocation) { scoped_refptr<TestContextProvider> context_provider = TestContextProvider::Create(); diff --git a/cc/scheduler/frame_rate_controller.cc b/cc/scheduler/frame_rate_controller.cc deleted file mode 100644 index beaa1e1..0000000 --- a/cc/scheduler/frame_rate_controller.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2011 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/scheduler/frame_rate_controller.h" - -#include "base/bind.h" -#include "base/debug/trace_event.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/single_thread_task_runner.h" -#include "cc/scheduler/delay_based_time_source.h" -#include "cc/scheduler/time_source.h" -#include "ui/gfx/frame_time.h" - -namespace cc { - -FrameRateController::FrameRateController(scoped_refptr<TimeSource> timer) - : client_(NULL), - interval_(BeginFrameArgs::DefaultInterval()), - time_source_(timer), - active_(false) { - time_source_->SetClient(this); -} - -FrameRateController::~FrameRateController() { time_source_->SetActive(false); } - -BeginFrameArgs FrameRateController::SetActive(bool active) { - if (active_ == active) - return BeginFrameArgs(); - TRACE_EVENT1("cc", "FrameRateController::SetActive", "active", active); - active_ = active; - - base::TimeTicks missed_tick_time = time_source_->SetActive(active); - if (!missed_tick_time.is_null()) { - base::TimeTicks deadline = NextTickTime(); - return BeginFrameArgs::Create( - missed_tick_time, deadline + deadline_adjustment_, interval_); - } - - return BeginFrameArgs(); -} - -void FrameRateController::SetTimebaseAndInterval(base::TimeTicks timebase, - base::TimeDelta interval) { - interval_ = interval; - time_source_->SetTimebaseAndInterval(timebase, interval); -} - -void FrameRateController::SetDeadlineAdjustment(base::TimeDelta delta) { - deadline_adjustment_ = delta; -} - -void FrameRateController::OnTimerTick() { - TRACE_EVENT0("cc", "FrameRateController::OnTimerTick"); - DCHECK(active_); - - if (client_) { - // TODO(brianderson): Use an adaptive parent compositor deadline. - base::TimeTicks frame_time = LastTickTime(); - base::TimeTicks deadline = NextTickTime(); - BeginFrameArgs args = BeginFrameArgs::Create( - frame_time, deadline + deadline_adjustment_, interval_); - client_->FrameRateControllerTick(args); - } -} - -base::TimeTicks FrameRateController::NextTickTime() { - return time_source_->NextTickTime(); -} - -base::TimeTicks FrameRateController::LastTickTime() { - return time_source_->LastTickTime(); -} - -} // namespace cc diff --git a/cc/scheduler/frame_rate_controller.h b/cc/scheduler/frame_rate_controller.h deleted file mode 100644 index 2ec62ac..0000000 --- a/cc/scheduler/frame_rate_controller.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2011 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_SCHEDULER_FRAME_RATE_CONTROLLER_H_ -#define CC_SCHEDULER_FRAME_RATE_CONTROLLER_H_ - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "cc/base/cc_export.h" -#include "cc/output/begin_frame_args.h" -#include "cc/scheduler/time_source.h" - -namespace base { class SingleThreadTaskRunner; } - -namespace cc { - -class TimeSource; -class FrameRateController; - -class CC_EXPORT FrameRateControllerClient { - protected: - virtual ~FrameRateControllerClient() {} - - public: - virtual void FrameRateControllerTick(const BeginFrameArgs& args) = 0; -}; - -// The FrameRateController is used in cases where we self-tick (i.e. BeginFrame -// is not sent by a parent compositor. -class CC_EXPORT FrameRateController : TimeSourceClient { - public: - explicit FrameRateController(scoped_refptr<TimeSource> timer); - virtual ~FrameRateController(); - - void SetClient(FrameRateControllerClient* client) { client_ = client; } - - // Returns a valid BeginFrame on activation to potentially be used - // retroactively. - BeginFrameArgs SetActive(bool active); - - bool IsActive() { return active_; } - - void SetTimebaseAndInterval(base::TimeTicks timebase, - base::TimeDelta interval); - void SetDeadlineAdjustment(base::TimeDelta delta); - - virtual void OnTimerTick() OVERRIDE; - - protected: - // This returns null for unthrottled frame-rate. - base::TimeTicks NextTickTime(); - // This returns now for unthrottled frame-rate. - base::TimeTicks LastTickTime(); - - FrameRateControllerClient* client_; - base::TimeDelta interval_; - base::TimeDelta deadline_adjustment_; - scoped_refptr<TimeSource> time_source_; - bool active_; - - private: - DISALLOW_COPY_AND_ASSIGN(FrameRateController); -}; - -} // namespace cc - -#endif // CC_SCHEDULER_FRAME_RATE_CONTROLLER_H_ diff --git a/cc/scheduler/frame_rate_controller_unittest.cc b/cc/scheduler/frame_rate_controller_unittest.cc deleted file mode 100644 index ed7de67..0000000 --- a/cc/scheduler/frame_rate_controller_unittest.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2011 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/scheduler/frame_rate_controller.h" - -#include "base/test/test_simple_task_runner.h" -#include "cc/test/scheduler_test_common.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -class FakeFrameRateControllerClient : public FrameRateControllerClient { - public: - FakeFrameRateControllerClient() { Reset(); } - - void Reset() { frame_count_ = 0; } - bool BeganFrame() const { return frame_count_ > 0; } - int frame_count() const { return frame_count_; } - - virtual void FrameRateControllerTick(const BeginFrameArgs& args) OVERRIDE { - frame_count_ += 1; - } - - protected: - int frame_count_; -}; - -TEST(FrameRateControllerTest, TestFrameThrottling_ImmediateAck) { - scoped_refptr<base::TestSimpleTaskRunner> task_runner = - new base::TestSimpleTaskRunner; - FakeFrameRateControllerClient client; - base::TimeDelta interval = base::TimeDelta::FromMicroseconds( - base::Time::kMicrosecondsPerSecond / 60); - scoped_refptr<FakeDelayBasedTimeSource> time_source = - FakeDelayBasedTimeSource::Create(interval, task_runner.get()); - FrameRateController controller(time_source); - - controller.SetClient(&client); - controller.SetActive(true); - - base::TimeTicks elapsed; // Muck around with time a bit - - // Trigger one frame, make sure the BeginFrame callback is called - elapsed += task_runner->NextPendingTaskDelay(); - time_source->SetNow(elapsed); - task_runner->RunPendingTasks(); - EXPECT_TRUE(client.BeganFrame()); - client.Reset(); - - // Trigger another frame, make sure BeginFrame runs again - elapsed += task_runner->NextPendingTaskDelay(); - // Sanity check that previous code didn't move time backward. - EXPECT_GE(elapsed, time_source->Now()); - time_source->SetNow(elapsed); - task_runner->RunPendingTasks(); - EXPECT_TRUE(client.BeganFrame()); -} - -} // namespace -} // namespace cc diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 592cbf1..df7f166 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -10,20 +10,77 @@ #include "base/logging.h" #include "cc/debug/devtools_instrumentation.h" #include "cc/debug/traced_value.h" +#include "cc/scheduler/delay_based_time_source.h" #include "ui/gfx/frame_time.h" namespace cc { +class SyntheticBeginFrameSource : public TimeSourceClient { + public: + SyntheticBeginFrameSource(Scheduler* scheduler, + base::SingleThreadTaskRunner* task_runner) + : scheduler_(scheduler) { + if (gfx::FrameTime::TimestampsAreHighRes()) { + time_source_ = DelayBasedTimeSourceHighRes::Create( + scheduler_->VSyncInterval(), task_runner); + } else { + time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(), + task_runner); + } + time_source_->SetClient(this); + } + + virtual ~SyntheticBeginFrameSource() {} + + // Updates the phase and frequency of the timer. + void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + time_source_->SetTimebaseAndInterval(timebase, interval); + } + + // Activates future BeginFrames and, if activating, pushes the most + // recently missed BeginFrame to the back of a retroactive queue. + void SetNeedsBeginFrame(bool needs_begin_frame, + std::deque<BeginFrameArgs>* begin_retro_frame_args) { + base::TimeTicks missed_tick_time = + time_source_->SetActive(needs_begin_frame); + if (!missed_tick_time.is_null()) { + begin_retro_frame_args->push_back( + CreateSyntheticBeginFrameArgs(missed_tick_time)); + } + } + + // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame. + virtual void OnTimerTick() OVERRIDE { + BeginFrameArgs begin_frame_args( + CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); + scheduler_->BeginFrame(begin_frame_args); + } + + private: + BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time) { + base::TimeTicks deadline = + time_source_->NextTickTime() - scheduler_->EstimatedParentDrawTime(); + return BeginFrameArgs::Create( + frame_time, deadline, scheduler_->VSyncInterval()); + } + + Scheduler* scheduler_; + scoped_refptr<TimeSource> time_source_; +}; + Scheduler::Scheduler( SchedulerClient* client, const SchedulerSettings& scheduler_settings, int layer_tree_host_id, - const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner) + const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) : settings_(scheduler_settings), client_(client), layer_tree_host_id_(layer_tree_host_id), impl_task_runner_(impl_task_runner), + vsync_interval_(BeginFrameArgs::DefaultInterval()), last_set_needs_begin_frame_(false), + begin_unthrottled_frame_posted_(false), begin_retro_frame_posted_(false), state_machine_(scheduler_settings), inside_process_scheduled_actions_(false), @@ -37,15 +94,46 @@ Scheduler::Scheduler( begin_retro_frame_closure_ = base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); + begin_unthrottled_frame_closure_ = + base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr()); begin_impl_frame_deadline_closure_ = base::Bind( &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); poll_for_draw_triggers_closure_ = base::Bind( &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); advance_commit_state_closure_ = base::Bind( &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); + + if (!settings_.begin_frame_scheduling_enabled) { + SetupSyntheticBeginFrames(); + } +} + +Scheduler::~Scheduler() { + if (synthetic_begin_frame_source_) { + synthetic_begin_frame_source_->SetNeedsBeginFrame(false, + &begin_retro_frame_args_); + } } -Scheduler::~Scheduler() {} +void Scheduler::SetupSyntheticBeginFrames() { + DCHECK(!synthetic_begin_frame_source_); + synthetic_begin_frame_source_.reset( + new SyntheticBeginFrameSource(this, impl_task_runner_.get())); +} + +void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + // TODO(brianderson): We should not be receiving 0 intervals. + if (interval == base::TimeDelta()) + interval = BeginFrameArgs::DefaultInterval(); + vsync_interval_ = interval; + if (!settings_.begin_frame_scheduling_enabled) + synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); +} + +void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { + estimated_parent_draw_time_ = draw_time; +} void Scheduler::SetCanStart() { state_machine_.SetCanStart(); @@ -176,6 +264,18 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() { void Scheduler::SetupNextBeginFrameIfNeeded() { bool needs_begin_frame = state_machine_.BeginFrameNeeded(); + if (settings_.throttle_frame_production) { + SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); + } else { + SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); + } + SetupPollingMechanisms(needs_begin_frame); +} + +// When we are throttling frame production, we request BeginFrames +// from the OutputSurface. +void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled( + bool needs_begin_frame) { bool at_end_of_deadline = state_machine_.begin_impl_frame_state() == SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; @@ -183,18 +283,61 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { bool should_call_set_needs_begin_frame = // Always request the BeginFrame immediately if it wasn't needed before. (needs_begin_frame && !last_set_needs_begin_frame_) || - // We always need to explicitly request our next BeginFrame. - at_end_of_deadline; + // Only stop requesting BeginFrames after a deadline. + (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline); if (should_call_set_needs_begin_frame) { - client_->SetNeedsBeginFrame(needs_begin_frame); + if (settings_.begin_frame_scheduling_enabled) { + client_->SetNeedsBeginFrame(needs_begin_frame); + } else { + synthetic_begin_frame_source_->SetNeedsBeginFrame( + needs_begin_frame, &begin_retro_frame_args_); + } last_set_needs_begin_frame_ = needs_begin_frame; } - // Handle retroactive BeginFrames. - if (last_set_needs_begin_frame_) - PostBeginRetroFrameIfNeeded(); + PostBeginRetroFrameIfNeeded(); +} + +// When we aren't throttling frame production, we initiate a BeginFrame +// as soon as one is needed. +void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled( + bool needs_begin_frame) { + last_set_needs_begin_frame_ = needs_begin_frame; + if (!needs_begin_frame || begin_unthrottled_frame_posted_) + return; + + if (state_machine_.begin_impl_frame_state() != + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && + state_machine_.begin_impl_frame_state() != + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { + return; + } + + begin_unthrottled_frame_posted_ = true; + impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); +} + +// BeginUnthrottledFrame is used when we aren't throttling frame production. +// This will usually be because VSync is disabled. +void Scheduler::BeginUnthrottledFrame() { + DCHECK(!settings_.throttle_frame_production); + DCHECK(begin_retro_frame_args_.empty()); + + base::TimeTicks now = gfx::FrameTime::Now(); + base::TimeTicks deadline = now + vsync_interval_; + + BeginFrameArgs begin_frame_args = + BeginFrameArgs::Create(now, deadline, vsync_interval_); + BeginImplFrame(begin_frame_args); + + begin_unthrottled_frame_posted_ = false; +} + +// We may need to poll when we can't rely on BeginFrame to advance certain +// state or to avoid deadlock. +void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { bool needs_advance_commit_state_timer = false; // Setup PollForAnticipatedDrawTriggers if we need to monitor state but // aren't expecting any more BeginFrames. This should only be needed by @@ -246,6 +389,9 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { // If the scheduler is busy, we queue the BeginFrame to be handled later as // a BeginRetroFrame. void Scheduler::BeginFrame(const BeginFrameArgs& args) { + TRACE_EVENT0("cc", "Scheduler::BeginFrame"); + DCHECK(settings_.throttle_frame_production); + bool should_defer_begin_frame; if (settings_.using_synchronous_renderer_compositor) { should_defer_begin_frame = false; @@ -272,9 +418,13 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) { void Scheduler::BeginRetroFrame() { TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); DCHECK(begin_retro_frame_posted_); - DCHECK(!begin_retro_frame_args_.empty()); DCHECK(!settings_.using_synchronous_renderer_compositor); + // If there aren't any retroactive BeginFrames, then we've lost the + // OutputSurface and should abort. + if (begin_retro_frame_args_.empty()) + return; + // Discard expired BeginRetroFrames // Today, we should always end up with at most one un-expired BeginRetroFrame // because deadlines will not be greater than the next frame time. We don't @@ -291,6 +441,7 @@ void Scheduler::BeginRetroFrame() { } if (begin_retro_frame_args_.empty()) { + DCHECK(settings_.throttle_frame_production); TRACE_EVENT_INSTANT0( "cc", "Scheduler::BeginRetroFrames expired", TRACE_EVENT_SCOPE_THREAD); } else { @@ -306,6 +457,9 @@ void Scheduler::BeginRetroFrame() { // will check if there is a pending BeginRetroFrame to ensure we handle // BeginFrames in FIFO order. void Scheduler::PostBeginRetroFrameIfNeeded() { + if (!last_set_needs_begin_frame_) + return; + if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) return; diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 7dd531b..0d34f03 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h @@ -17,11 +17,13 @@ #include "cc/scheduler/draw_swap_readback_result.h" #include "cc/scheduler/scheduler_settings.h" #include "cc/scheduler/scheduler_state_machine.h" +#include "cc/scheduler/time_source.h" #include "cc/trees/layer_tree_host.h" namespace cc { class Thread; +class SyntheticBeginFrameSource; class SchedulerClient { public: @@ -52,13 +54,19 @@ class CC_EXPORT Scheduler { SchedulerClient* client, const SchedulerSettings& scheduler_settings, int layer_tree_host_id, - const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner) { + const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) { return make_scoped_ptr(new Scheduler( client, scheduler_settings, layer_tree_host_id, impl_task_runner)); } virtual ~Scheduler(); + const SchedulerSettings& settings() const { return settings_; } + + void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval); + void SetEstimatedParentDrawTime(base::TimeDelta draw_time); + void SetCanStart(); void SetVisible(bool visible); @@ -111,9 +119,16 @@ class CC_EXPORT Scheduler { void NotifyBeginMainFrameStarted(); base::TimeTicks LastBeginImplFrameTime(); + base::TimeDelta VSyncInterval() { return vsync_interval_; } + base::TimeDelta EstimatedParentDrawTime() { + return estimated_parent_draw_time_; + } void BeginFrame(const BeginFrameArgs& args); + void PostBeginRetroFrame(); void BeginRetroFrame(); + void BeginUnthrottledFrame(); + void BeginImplFrame(const BeginFrameArgs& args); void OnBeginImplFrameDeadline(); void PollForAnticipatedDrawTriggers(); @@ -131,10 +146,11 @@ class CC_EXPORT Scheduler { } private: - Scheduler(SchedulerClient* client, - const SchedulerSettings& scheduler_settings, - int layer_tree_host_id, - const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner); + Scheduler( + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id, + const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner); base::TimeTicks AdjustedBeginImplFrameDeadline( const BeginFrameArgs& args, @@ -142,6 +158,9 @@ class CC_EXPORT Scheduler { void ScheduleBeginImplFrameDeadline(base::TimeTicks deadline); void SetupNextBeginFrameIfNeeded(); void PostBeginRetroFrameIfNeeded(); + void SetupNextBeginFrameWhenVSyncThrottlingEnabled(bool needs_begin_frame); + void SetupNextBeginFrameWhenVSyncThrottlingDisabled(bool needs_begin_frame); + void SetupPollingMechanisms(bool needs_begin_frame); void ActivatePendingTree(); void DrawAndSwapIfPossible(); void DrawAndSwapForced(); @@ -156,15 +175,23 @@ class CC_EXPORT Scheduler { const SchedulerSettings settings_; SchedulerClient* client_; int layer_tree_host_id_; - scoped_refptr<base::SequencedTaskRunner> impl_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_; + + base::TimeDelta vsync_interval_; + base::TimeDelta estimated_parent_draw_time_; bool last_set_needs_begin_frame_; + bool begin_unthrottled_frame_posted_; bool begin_retro_frame_posted_; - std::deque<BeginFrameArgs> begin_retro_frame_args_; BeginFrameArgs begin_impl_frame_args_; + void SetupSyntheticBeginFrames(); + scoped_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source_; + base::Closure begin_retro_frame_closure_; + base::Closure begin_unthrottled_frame_closure_; + base::Closure begin_impl_frame_deadline_closure_; base::Closure poll_for_draw_triggers_closure_; base::Closure advance_commit_state_closure_; diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc index 808a9fa..7a951aa 100644 --- a/cc/scheduler/scheduler_settings.cc +++ b/cc/scheduler/scheduler_settings.cc @@ -7,13 +7,15 @@ namespace cc { SchedulerSettings::SchedulerSettings() - : main_frame_before_draw_enabled(true), + : begin_frame_scheduling_enabled(true), + main_frame_before_draw_enabled(true), main_frame_before_activation_enabled(false), impl_side_painting(false), timeout_and_draw_when_animation_checkerboards(true), maximum_number_of_failed_draws_before_draw_is_forced_(3), using_synchronous_renderer_compositor(false), - throttle_frame_production(true) {} + throttle_frame_production(true) { +} SchedulerSettings::~SchedulerSettings() {} diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h index 4b2f664..f8e913f 100644 --- a/cc/scheduler/scheduler_settings.h +++ b/cc/scheduler/scheduler_settings.h @@ -14,6 +14,7 @@ class CC_EXPORT SchedulerSettings { SchedulerSettings(); ~SchedulerSettings(); + bool begin_frame_scheduling_enabled; bool main_frame_before_draw_enabled; bool main_frame_before_activation_enabled; bool impl_side_painting; diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 7b2bb43..647af71 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc @@ -801,10 +801,13 @@ bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { return false; } +// Note: If SupportsProactiveBeginFrame is false, the scheduler should poll +// for changes in it's draw state so it can request a BeginFrame when it's +// actually ready. bool SchedulerStateMachine::SupportsProactiveBeginFrame() const { - // Both the synchronous compositor and disabled vsync settings - // make it undesirable to proactively request BeginImplFrames. - // If this is true, the scheduler should poll. + // It is undesirable to proactively request BeginFrames if we are + // using a synchronous compositor because we *must* draw for every + // BeginFrame, which could cause duplicate draws. return !settings_.using_synchronous_renderer_compositor; } diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 21e20ea..a5d279b 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc @@ -39,8 +39,7 @@ void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, class FakeSchedulerClient : public SchedulerClient { public: - FakeSchedulerClient() - : needs_begin_impl_frame_(false), automatic_swap_ack_(true) { + FakeSchedulerClient() : needs_begin_frame_(false), automatic_swap_ack_(true) { Reset(); } @@ -64,7 +63,7 @@ class FakeSchedulerClient : public SchedulerClient { void set_log_anticipated_draw_time_change(bool log) { log_anticipated_draw_time_change_ = log; } - bool needs_begin_impl_frame() { return needs_begin_impl_frame_; } + bool needs_begin_frame() { return needs_begin_frame_; } int num_draws() const { return num_draws_; } int num_actions_() const { return static_cast<int>(actions_.size()); } const char* Action(int i) const { return actions_[i]; } @@ -100,7 +99,7 @@ class FakeSchedulerClient : public SchedulerClient { virtual void SetNeedsBeginFrame(bool enable) OVERRIDE { actions_.push_back("SetNeedsBeginFrame"); states_.push_back(scheduler_->StateAsValue().release()); - needs_begin_impl_frame_ = enable; + needs_begin_frame_ = enable; } virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE { actions_.push_back("WillBeginImplFrame"); @@ -185,7 +184,7 @@ class FakeSchedulerClient : public SchedulerClient { virtual void DidBeginImplFrameDeadline() OVERRIDE {} protected: - bool needs_begin_impl_frame_; + bool needs_begin_frame_; bool draw_will_happen_; bool swap_will_happen_if_draw_happens_; bool automatic_swap_ack_; @@ -200,12 +199,19 @@ class FakeSchedulerClient : public SchedulerClient { void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, FakeSchedulerClient* client) { + bool client_initiates_begin_frame = + scheduler->settings().begin_frame_scheduling_enabled && + scheduler->settings().throttle_frame_production; + scheduler->DidCreateAndInitializeOutputSurface(); scheduler->SetNeedsCommit(); scheduler->NotifyBeginMainFrameStarted(); scheduler->NotifyReadyToCommit(); // Go through the motions to draw the commit. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (client_initiates_begin_frame) + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + else + client->task_runner().RunPendingTasks(); // Run posted BeginFrame. // Run the posted deadline task. EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -214,7 +220,10 @@ void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, // We need another BeginImplFrame so Scheduler calls // SetNeedsBeginFrame(false). - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (client_initiates_begin_frame) + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + else + client->task_runner().RunPendingTasks(); // Run posted BeginFrame. // Run the posted deadline task. EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -250,7 +259,7 @@ TEST(SchedulerTest, RequestCommit) { // SetNeedsCommit should begin the frame on the next BeginImplFrame. client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); @@ -258,37 +267,35 @@ TEST(SchedulerTest, RequestCommit) { EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); - // If we don't swap on the deadline, we need to request another - // BeginImplFrame. + // If we don't swap on the deadline, we wait for the next BeginFrame. client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); + EXPECT_EQ(0, client.num_actions_()); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // NotifyReadyToCommit should trigger the commit. scheduler->NotifyBeginMainFrameStarted(); scheduler->NotifyReadyToCommit(); EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // BeginImplFrame should prepare the draw. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // BeginImplFrame deadline should draw. client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrame", client, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) @@ -300,7 +307,7 @@ TEST(SchedulerTest, RequestCommit) { client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); } @@ -326,7 +333,7 @@ TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Now SetNeedsCommit again. Calling here means we need a second commit. @@ -341,13 +348,12 @@ TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrame", client, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); // Because we just swapped, the Scheduler should also request the next // BeginImplFrame from the OutputSurface. - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Since another commit is needed, the next BeginImplFrame should initiate // the second commit. @@ -365,17 +371,16 @@ TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrame", client, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // On the next BeginImplFrame, verify we go back to a quiescent state and // no longer request BeginImplFrames. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); } @@ -419,20 +424,20 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // We stop requesting BeginImplFrames after a BeginImplFrame where we don't // swap. @@ -440,7 +445,7 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); } // Test that requesting redraw inside a failed draw doesn't lose the request. @@ -458,7 +463,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); // Fail the draw. @@ -470,7 +475,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { // request. EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // Fail the draw again. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); @@ -478,7 +483,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // Draw successfully. client.SetDrawWillHappen(true); @@ -487,7 +492,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); } class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { @@ -536,11 +541,11 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { InitializeOutputSurfaceAndFirstCommit(scheduler, &client); client.Reset(); - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_EQ(0, client.num_draws()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.SetNeedsCommitOnNextDraw(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); @@ -548,7 +553,7 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); scheduler->NotifyBeginMainFrameStarted(); scheduler->NotifyReadyToCommit(); @@ -558,7 +563,7 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->CommitPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // We stop requesting BeginImplFrames after a BeginImplFrame where we don't // swap. @@ -567,7 +572,7 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->CommitPending()); - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); } // Tests that when a draw fails then the pending commit should not be dropped. @@ -585,7 +590,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); // Fail the draw. @@ -597,7 +602,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { // request. EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // Fail the draw again. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); @@ -606,7 +611,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // Draw successfully. client.SetDrawWillHappen(true); @@ -615,7 +620,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); } TEST(SchedulerTest, NoSwapWhenDrawFails) { @@ -630,7 +635,7 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); // Draw successfully, this starts a new frame. @@ -641,7 +646,7 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); // Fail to draw, this should not start a frame. client.SetDrawWillHappen(false); @@ -724,7 +729,7 @@ TEST(SchedulerTest, ManageTiles) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_TRUE(scheduler->ManageTilesPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); @@ -753,7 +758,7 @@ TEST(SchedulerTest, ManageTiles) { scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->ManageTilesPending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); // We have no immediate actions to perform, so the BeginImplFrame should post @@ -785,15 +790,16 @@ TEST(SchedulerTest, ManageTiles) { client.Reset(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); + EXPECT_FALSE(client.needs_begin_frame()); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); EXPECT_EQ(0, client.num_draws()); // Now trigger a ManageTiles outside of a draw. We will then need // a begin-frame for the ManageTiles, but we don't need a draw. client.Reset(); - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); scheduler->SetNeedsManageTiles(); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_TRUE(scheduler->ManageTilesPending()); EXPECT_FALSE(scheduler->RedrawPending()); @@ -1116,7 +1122,7 @@ TEST(SchedulerTest, PollForCommitCompletion) { } } -TEST(SchedulerTest, BeginRetroFrameBasic) { +TEST(SchedulerTest, BeginRetroFrame) { FakeSchedulerClient client; SchedulerSettings scheduler_settings; Scheduler* scheduler = client.CreateScheduler(scheduler_settings); @@ -1128,7 +1134,7 @@ TEST(SchedulerTest, BeginRetroFrameBasic) { // SetNeedsCommit should begin the frame on the next BeginImplFrame. client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); @@ -1140,7 +1146,7 @@ TEST(SchedulerTest, BeginRetroFrameBasic) { EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Queue BeginFrames while we are still handling the previous BeginFrame. @@ -1149,34 +1155,32 @@ TEST(SchedulerTest, BeginRetroFrameBasic) { args.frame_time += base::TimeDelta::FromSeconds(1); scheduler->BeginFrame(args); - // If we don't swap on the deadline, we need to request another - // BeginImplFrame. + // If we don't swap on the deadline, we wait for the next BeginImplFrame. client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); + EXPECT_EQ(0, client.num_actions_()); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // NotifyReadyToCommit should trigger the commit. scheduler->NotifyBeginMainFrameStarted(); scheduler->NotifyReadyToCommit(); EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // BeginImplFrame should prepare the draw. client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // BeginImplFrame deadline should draw. client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrame", client, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) @@ -1188,7 +1192,7 @@ TEST(SchedulerTest, BeginRetroFrameBasic) { client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); - EXPECT_FALSE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); } @@ -1208,7 +1212,7 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { // SetNeedsCommit should begin the frame on the next BeginImplFrame. client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); @@ -1220,7 +1224,7 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Queue BeginFrame while we are still handling the previous BeginFrame. @@ -1235,15 +1239,14 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { scheduler->NotifyBeginMainFrameStarted(); scheduler->NotifyReadyToCommit(); EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Swapping will put us into a swap throttled state. client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrame", client, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // While swap throttled, BeginRetroFrames should trigger BeginImplFrames @@ -1252,7 +1255,7 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame. EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Queue BeginFrame while we are still handling the previous BeginFrame. @@ -1260,24 +1263,210 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { scheduler->BeginFrame(args); EXPECT_EQ(0, client.num_actions_()); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // Take us out of a swap throttled state. scheduler->DidSwapBuffersComplete(); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // BeginImplFrame deadline should draw. scheduler->SetNeedsRedraw(); client.task_runner().RunPendingTasks(); // Run posted deadline. - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrame", client, 1, 2); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); + EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); +} + +void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled, + bool throttle_frame_production) { + FakeSchedulerClient client; + SchedulerSettings scheduler_settings; + scheduler_settings.begin_frame_scheduling_enabled = + begin_frame_scheduling_enabled; + scheduler_settings.throttle_frame_production = throttle_frame_production; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->SetCanDraw(true); + InitializeOutputSurfaceAndFirstCommit(scheduler, &client); + + // SetNeedsCommit should begin the frame on the next BeginImplFrame + // without calling SetNeedsBeginFrame. + client.Reset(); + scheduler->SetNeedsCommit(); + EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_EQ(0, client.num_actions_()); + client.Reset(); + + // When the client-driven BeginFrame are disabled, the scheduler posts it's + // own BeginFrame tasks. + client.task_runner().RunPendingTasks(); // Run posted BeginFrame. + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // If we don't swap on the deadline, we wait for the next BeginFrame. + client.task_runner().RunPendingTasks(); // Run posted deadline. + EXPECT_EQ(0, client.num_actions_()); + EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // NotifyReadyToCommit should trigger the commit. + scheduler->NotifyBeginMainFrameStarted(); + scheduler->NotifyReadyToCommit(); + EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // BeginImplFrame should prepare the draw. + client.task_runner().RunPendingTasks(); // Run posted BeginFrame. + EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // BeginImplFrame deadline should draw. + client.task_runner().RunPendingTasks(); // Run posted deadline. + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); - EXPECT_TRUE(client.needs_begin_impl_frame()); + EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); + + // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) + // to avoid excessive toggles. + client.task_runner().RunPendingTasks(); // Run posted BeginFrame. + EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + client.Reset(); + + // Make sure SetNeedsBeginFrame isn't called on the client + // when the BeginFrame is no longer needed. + client.task_runner().RunPendingTasks(); // Run posted deadline. + EXPECT_EQ(0, client.num_actions_()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); +} + +TEST(SchedulerTest, SyntheticBeginFrames) { + bool begin_frame_scheduling_enabled = false; + bool throttle_frame_production = true; + BeginFramesNotFromClient(begin_frame_scheduling_enabled, + throttle_frame_production); +} + +TEST(SchedulerTest, VSyncThrottlingDisabled) { + bool begin_frame_scheduling_enabled = true; + bool throttle_frame_production = false; + BeginFramesNotFromClient(begin_frame_scheduling_enabled, + throttle_frame_production); +} + +TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) { + bool begin_frame_scheduling_enabled = false; + bool throttle_frame_production = false; + BeginFramesNotFromClient(begin_frame_scheduling_enabled, + throttle_frame_production); +} + +void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled, + bool throttle_frame_production) { + FakeSchedulerClient client; + SchedulerSettings scheduler_settings; + scheduler_settings.begin_frame_scheduling_enabled = + begin_frame_scheduling_enabled; + scheduler_settings.throttle_frame_production = throttle_frame_production; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->SetCanDraw(true); + InitializeOutputSurfaceAndFirstCommit(scheduler, &client); + + // To test swap ack throttling, this test disables automatic swap acks. + scheduler->SetMaxSwapsPending(1); + client.SetAutomaticSwapAck(false); + + // SetNeedsCommit should begin the frame on the next BeginImplFrame. + client.Reset(); + scheduler->SetNeedsCommit(); + EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_EQ(0, client.num_actions_()); + client.Reset(); + + // Trigger the first BeginImplFrame and BeginMainFrame + client.task_runner().RunPendingTasks(); // Run posted BeginFrame. + EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // NotifyReadyToCommit should trigger the pending commit and draw. + scheduler->NotifyBeginMainFrameStarted(); + scheduler->NotifyReadyToCommit(); + EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // Swapping will put us into a swap throttled state. + client.task_runner().RunPendingTasks(); // Run posted deadline. + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); + EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // While swap throttled, BeginFrames should trigger BeginImplFrames, + // but not a BeginMainFrame or draw. + scheduler->SetNeedsCommit(); + client.task_runner().RunPendingTasks(); // Run posted BeginFrame. + EXPECT_ACTION("WillBeginImplFrame", client, 0, 1); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // Take us out of a swap throttled state. + scheduler->DidSwapBuffersComplete(); + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1); + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); + + // BeginImplFrame deadline should draw. + scheduler->SetNeedsRedraw(); + client.task_runner().RunPendingTasks(); // Run posted deadline. + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); + EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); + EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); +} + +TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) { + bool begin_frame_scheduling_enabled = false; + bool throttle_frame_production = true; + BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, + throttle_frame_production); +} + +TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) { + bool begin_frame_scheduling_enabled = true; + bool throttle_frame_production = false; + BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, + throttle_frame_production); +} + +TEST(SchedulerTest, + SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) { + bool begin_frame_scheduling_enabled = false; + bool throttle_frame_production = false; + BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, + throttle_frame_production); } } // namespace diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h index bdbea22..57350bf 100644 --- a/cc/test/fake_layer_tree_host_impl_client.h +++ b/cc/test/fake_layer_tree_host_impl_client.h @@ -15,6 +15,9 @@ class FakeLayerTreeHostImplClient : public LayerTreeHostImplClient { // LayerTreeHostImplClient implementation. virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE {} virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {} + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE {} + virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE {} virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {} virtual void DidSwapBuffersOnImplThread() OVERRIDE {} virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE {} diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc index 920b689..352b6e4 100644 --- a/cc/test/fake_output_surface.cc +++ b/cc/test/fake_output_surface.cc @@ -76,7 +76,7 @@ void FakeOutputSurface::SwapBuffers(CompositorFrame* frame) { ++num_sent_frames_; PostSwapBuffersComplete(); - DidSwapBuffers(); + client_->DidSwapBuffers(); } else { OutputSurface::SwapBuffers(frame); frame->AssignTo(&last_sent_frame_); @@ -88,9 +88,7 @@ void FakeOutputSurface::SetNeedsBeginFrame(bool enable) { needs_begin_frame_ = enable; OutputSurface::SetNeedsBeginFrame(enable); - // If there is not BeginFrame emulation from the FrameRateController, - // then we just post a BeginFrame to emulate it as part of the test. - if (enable && !frame_rate_controller_) { + if (enable) { base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&FakeOutputSurface::OnBeginFrame, @@ -100,7 +98,7 @@ void FakeOutputSurface::SetNeedsBeginFrame(bool enable) { } void FakeOutputSurface::OnBeginFrame() { - OutputSurface::BeginFrame(BeginFrameArgs::CreateForTesting()); + client_->BeginFrame(BeginFrameArgs::CreateForTesting()); } diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h index 4f0486a..0548bde 100644 --- a/cc/test/fake_output_surface_client.h +++ b/cc/test/fake_output_surface_client.h @@ -20,6 +20,8 @@ class FakeOutputSurfaceClient : public OutputSurfaceClient { virtual void DeferredInitialize() OVERRIDE; virtual void ReleaseGL() OVERRIDE {} + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE {} virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) OVERRIDE {} virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; virtual void DidSwapBuffers() OVERRIDE {} diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 071332d..596358a 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h @@ -9,7 +9,6 @@ #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "cc/scheduler/delay_based_time_source.h" -#include "cc/scheduler/frame_rate_controller.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -47,12 +46,6 @@ class FakeDelayBasedTimeSource : public DelayBasedTimeSource { base::TimeTicks now_; }; -class FakeFrameRateController : public FrameRateController { - public: - explicit FakeFrameRateController(scoped_refptr<TimeSource> timer) - : FrameRateController(timer) {} -}; - } // namespace cc #endif // CC_TEST_SCHEDULER_TEST_COMMON_H_ diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 679e0e7..36c71ce 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -1503,6 +1503,8 @@ bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) { void LayerTreeHostImpl::SetNeedsBeginFrame(bool enable) { if (output_surface_) output_surface_->SetNeedsBeginFrame(enable); + else + DCHECK(!enable); } void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) { @@ -1886,20 +1888,18 @@ bool LayerTreeHostImpl::InitializeRenderer( GetRendererCapabilities().allow_rasterize_on_demand); } - if (!settings_.throttle_frame_production) { - // Disable VSync - output_surface->SetThrottleFrameProduction(false); - } else if (!settings_.begin_impl_frame_scheduling_enabled) { - // Setup BeginFrameEmulation if it's not supported natively - const base::TimeDelta display_refresh_interval = - base::TimeDelta::FromMicroseconds( - base::Time::kMicrosecondsPerSecond / - settings_.refresh_rate); + // Initialize vsync parameters to sane values. + const base::TimeDelta display_refresh_interval = + base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond / + settings_.refresh_rate); + CommitVSyncParameters(base::TimeTicks(), display_refresh_interval); - output_surface->InitializeBeginFrameEmulation( - proxy_->ImplThreadTaskRunner(), - display_refresh_interval); - } + // TODO(brianderson): Don't use a hard-coded parent draw time. + base::TimeDelta parent_draw_time = + output_surface->capabilities().adjust_deadline_for_parent + ? BeginFrameArgs::DefaultDeadlineAdjustment() + : base::TimeDelta(); + client_->SetEstimatedParentDrawTime(parent_draw_time); int max_frames_pending = output_surface->capabilities().max_frames_pending; @@ -1915,6 +1915,11 @@ bool LayerTreeHostImpl::InitializeRenderer( return true; } +void LayerTreeHostImpl::CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + client_->CommitVSyncParameters(timebase, interval); +} + void LayerTreeHostImpl::DeferredInitialize() { DCHECK(output_surface_->capabilities().deferred_gl_initialization); DCHECK(settings_.impl_side_painting); diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index d0b6e1a..aa8addc 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h @@ -63,6 +63,9 @@ class LayerTreeHostImplClient { public: virtual void UpdateRendererCapabilitiesOnImplThread() = 0; virtual void DidLoseOutputSurfaceOnImplThread() = 0; + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) = 0; + virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) = 0; virtual void SetMaxSwapsPendingOnImplThread(int max) = 0; virtual void DidSwapBuffersOnImplThread() = 0; virtual void DidSwapBuffersCompleteOnImplThread() = 0; @@ -224,6 +227,8 @@ class CC_EXPORT LayerTreeHostImpl // OutputSurfaceClient implementation. virtual void DeferredInitialize() OVERRIDE; virtual void ReleaseGL() OVERRIDE; + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE; virtual void SetNeedsRedrawRect(const gfx::Rect& rect) OVERRIDE; virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; virtual void SetExternalDrawConstraints( diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 0a2da1f..0aaeb3e 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -110,6 +110,9 @@ class LayerTreeHostImplTest : public testing::Test, virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE {} virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {} + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE {} + virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE {} virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {} virtual void DidSwapBuffersOnImplThread() OVERRIDE {} virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE {} diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 56f2a17..e942bc7 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -26,7 +26,6 @@ #include "cc/resources/prioritized_resource.h" #include "cc/resources/prioritized_resource_manager.h" #include "cc/resources/resource_update_queue.h" -#include "cc/scheduler/frame_rate_controller.h" #include "cc/test/fake_content_layer.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_content_layer_impl.h" @@ -2604,7 +2603,7 @@ SINGLE_THREAD_TEST_F(LayerTreeHostTestLCDNotification); class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest { public: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->begin_impl_frame_scheduling_enabled = true; + settings->begin_frame_scheduling_enabled = true; } virtual void BeginTest() OVERRIDE { @@ -2633,7 +2632,7 @@ class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled : public LayerTreeHostTest { public: virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->begin_impl_frame_scheduling_enabled = true; + settings->begin_frame_scheduling_enabled = true; settings->using_synchronous_renderer_compositor = true; } @@ -2660,7 +2659,7 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest { : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {} virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { - settings->begin_impl_frame_scheduling_enabled = true; + settings->begin_frame_scheduling_enabled = true; } virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc index 7ae0cde..7ac2a52 100644 --- a/cc/trees/layer_tree_settings.cc +++ b/cc/trees/layer_tree_settings.cc @@ -16,7 +16,7 @@ LayerTreeSettings::LayerTreeSettings() : impl_side_painting(false), allow_antialiasing(true), throttle_frame_production(true), - begin_impl_frame_scheduling_enabled(false), + begin_frame_scheduling_enabled(false), main_frame_before_draw_enabled(true), main_frame_before_activation_enabled(false), using_synchronous_renderer_compositor(false), @@ -60,7 +60,8 @@ LayerTreeSettings::LayerTreeSettings() ignore_root_layer_flings(false), use_rgba_4444_textures(false), touch_hit_testing(true), - texture_id_allocation_chunk_size(64) {} + texture_id_allocation_chunk_size(64) { +} LayerTreeSettings::~LayerTreeSettings() {} diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h index e85ef7d..b1097b5 100644 --- a/cc/trees/layer_tree_settings.h +++ b/cc/trees/layer_tree_settings.h @@ -21,7 +21,7 @@ class CC_EXPORT LayerTreeSettings { bool impl_side_painting; bool allow_antialiasing; bool throttle_frame_production; - bool begin_impl_frame_scheduling_enabled; + bool begin_frame_scheduling_enabled; bool main_frame_before_draw_enabled; bool main_frame_before_activation_enabled; bool using_synchronous_renderer_compositor; diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 2882551..e26e031 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h @@ -55,6 +55,9 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient { // LayerTreeHostImplClient implementation virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE; virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE; + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE {} + virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE {} virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {} virtual void DidSwapBuffersOnImplThread() OVERRIDE; virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE; diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc index 9e9abd3..97a0c94 100644 --- a/cc/trees/thread_proxy.cc +++ b/cc/trees/thread_proxy.cc @@ -21,7 +21,6 @@ #include "cc/quads/draw_quad.h" #include "cc/resources/prioritized_resource_manager.h" #include "cc/scheduler/delay_based_time_source.h" -#include "cc/scheduler/frame_rate_controller.h" #include "cc/scheduler/scheduler.h" #include "cc/trees/blocking_task_runner.h" #include "cc/trees/layer_tree_host.h" @@ -396,6 +395,15 @@ void ThreadProxy::CheckOutputSurfaceStatusOnImplThread() { impl().scheduler->DidLoseOutputSurface(); } +void ThreadProxy::CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + impl().scheduler->CommitVSyncParameters(timebase, interval); +} + +void ThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { + impl().scheduler->SetEstimatedParentDrawTime(draw_time); +} + void ThreadProxy::SetMaxSwapsPendingOnImplThread(int max) { impl().scheduler->SetMaxSwapsPending(max); } @@ -1372,6 +1380,8 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { layer_tree_host()->CreateLayerTreeHostImpl(this); const LayerTreeSettings& settings = layer_tree_host()->settings(); SchedulerSettings scheduler_settings; + scheduler_settings.begin_frame_scheduling_enabled = + settings.begin_frame_scheduling_enabled; scheduler_settings.main_frame_before_draw_enabled = settings.main_frame_before_draw_enabled; scheduler_settings.main_frame_before_activation_enabled = diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h index 60e5416..aab7a43 100644 --- a/cc/trees/thread_proxy.h +++ b/cc/trees/thread_proxy.h @@ -73,10 +73,13 @@ class ThreadProxy : public Proxy, // LayerTreeHostImplClient implementation virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE; virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE; + virtual void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE; + virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE; + virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE; virtual void DidSwapBuffersOnImplThread() OVERRIDE; virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE; - virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE; virtual void NotifyReadyToActivate() OVERRIDE; // Please call these 2 functions through diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc index edadb0e..de609c3 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc @@ -69,6 +69,7 @@ SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface( : cc::OutputSurface( scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))), routing_id_(routing_id), + needs_begin_frame_(false), invoking_composite_(false), did_swap_buffer_(false), current_sw_canvas_(NULL), @@ -126,7 +127,6 @@ void SynchronousCompositorOutputSurface::Reshape( void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(bool enable) { DCHECK(CalledOnValidThread()); needs_begin_frame_ = enable; - client_ready_for_begin_frame_ = true; SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); if (delegate && !invoking_composite_) delegate->SetContinuousInvalidate(needs_begin_frame_); @@ -142,7 +142,7 @@ void SynchronousCompositorOutputSurface::SwapBuffers( UpdateFrameMetaData(frame->metadata); did_swap_buffer_ = true; - DidSwapBuffers(); + client_->DidSwapBuffers(); } void SynchronousCompositorOutputSurface::UpdateFrameMetaData( @@ -236,7 +236,7 @@ void SynchronousCompositorOutputSurface::InvokeComposite( SetExternalDrawConstraints( adjusted_transform, viewport, clip, valid_for_tile_management); SetNeedsRedrawRect(gfx::Rect(viewport.size())); - BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor()); + client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor()); // After software draws (which might move the viewport arbitrarily), restore // the previous hardware viewport to allow CC's tile manager to prioritize @@ -251,18 +251,13 @@ void SynchronousCompositorOutputSurface::InvokeComposite( } if (did_swap_buffer_) - OnSwapBuffersComplete(); + client_->DidSwapBuffersComplete(); SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate(); if (delegate) delegate->SetContinuousInvalidate(needs_begin_frame_); } -void SynchronousCompositorOutputSurface::PostCheckForRetroactiveBeginFrame() { - // Synchronous compositor cannot perform retroactive BeginFrames, so - // intentionally no-op here. -} - void SynchronousCompositorOutputSurface::SetMemoryPolicy( const SynchronousCompositorMemoryPolicy& policy) { DCHECK(CalledOnValidThread()); diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.h b/content/browser/android/in_process/synchronous_compositor_output_surface.h index a703037..61f546f 100644 --- a/content/browser/android/in_process/synchronous_compositor_output_surface.h +++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h @@ -78,9 +78,6 @@ class SynchronousCompositorOutputSurface class SoftwareDevice; friend class SoftwareDevice; - // Private OutputSurface overrides. - virtual void PostCheckForRetroactiveBeginFrame() OVERRIDE; - void InvokeComposite(const gfx::Transform& transform, gfx::Rect viewport, gfx::Rect clip, @@ -90,6 +87,7 @@ class SynchronousCompositorOutputSurface void UpdateFrameMetaData(const cc::CompositorFrameMetadata& frame_info); int routing_id_; + bool needs_begin_frame_; bool invoking_composite_; bool did_swap_buffer_; diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 51e5af0..2ca5348 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -530,8 +530,7 @@ void RenderWidgetHostViewAndroid::SendBeginFrame( host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args)); } -void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame( - bool enabled) { +void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) { TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame", "enabled", enabled); // ContentViewCoreImpl handles multiple subscribers to the BeginFrame, so diff --git a/content/renderer/gpu/compositor_output_surface.cc b/content/renderer/gpu/compositor_output_surface.cc index dd9d632..c642441 100644 --- a/content/renderer/gpu/compositor_output_surface.cc +++ b/content/renderer/gpu/compositor_output_surface.cc @@ -157,7 +157,7 @@ void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { } else { base::MessageLoopProxy::current()->PostTask(FROM_HERE, closure); } - DidSwapBuffers(); + client_->DidSwapBuffers(); return; } @@ -165,7 +165,7 @@ void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { Send(new ViewHostMsg_SwapCompositorFrame(routing_id_, output_surface_id_, *frame)); - DidSwapBuffers(); + client_->DidSwapBuffers(); return; } @@ -207,14 +207,12 @@ void CompositorOutputSurface::OnUpdateVSyncParametersFromBrowser( #if defined(OS_ANDROID) void CompositorOutputSurface::SetNeedsBeginFrame(bool enable) { DCHECK(CalledOnValidThread()); - if (needs_begin_frame_ != enable) - Send(new ViewHostMsg_SetNeedsBeginFrame(routing_id_, enable)); - OutputSurface::SetNeedsBeginFrame(enable); + Send(new ViewHostMsg_SetNeedsBeginFrame(routing_id_, enable)); } void CompositorOutputSurface::OnBeginFrame(const cc::BeginFrameArgs& args) { DCHECK(CalledOnValidThread()); - BeginFrame(args); + client_->BeginFrame(args); } #endif // defined(OS_ANDROID) @@ -225,7 +223,7 @@ void CompositorOutputSurface::OnSwapAck(uint32 output_surface_id, if (output_surface_id != output_surface_id_) return; ReclaimResources(&ack); - OnSwapBuffersComplete(); + client_->DidSwapBuffersComplete(); } void CompositorOutputSurface::OnReclaimResources( diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 3a12e98..e10b3ca 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc @@ -90,7 +90,7 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create( settings.throttle_frame_production = !cmd->HasSwitch(switches::kDisableGpuVsync); - settings.begin_impl_frame_scheduling_enabled = + settings.begin_frame_scheduling_enabled = cmd->HasSwitch(switches::kEnableBeginFrameScheduling); settings.main_frame_before_activation_enabled = cmd->HasSwitch(cc::switches::kEnableMainFrameBeforeActivation) && |