Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(545)

Unified Diff: cc/surfaces/display_scheduler_unittest.cc

Issue 1138563002: Add DisplayScheduler for Surfaces (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@rendererLatencyRecoveryHeuristic
Patch Set: rebase Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/surfaces/display_scheduler.cc ('k') | cc/surfaces/display_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/surfaces/display_scheduler_unittest.cc
diff --git a/cc/surfaces/display_scheduler_unittest.cc b/cc/surfaces/display_scheduler_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ab526f8fee569d8d428646197e131b5a587aae93
--- /dev/null
+++ b/cc/surfaces/display_scheduler_unittest.cc
@@ -0,0 +1,321 @@
+// Copyright 2015 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/surfaces/display_scheduler.h"
+
+#include "base/logging.h"
+#include "base/test/null_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/output/begin_frame_args.h"
+#include "cc/surfaces/display.h"
+#include "cc/test/scheduler_test_common.h"
+#include "cc/test/test_now_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class FakeDisplaySchedulerClient : public DisplaySchedulerClient {
+ public:
+ FakeDisplaySchedulerClient() : draw_and_swap_count_(0) {}
+
+ ~FakeDisplaySchedulerClient() override {}
+
+ bool DrawAndSwap() override {
+ draw_and_swap_count_++;
+ return true;
+ }
+
+ void Reset() { draw_and_swap_count_ = 0; }
+
+ int draw_and_swap_count() const { return draw_and_swap_count_; }
+
+ protected:
+ int draw_and_swap_count_;
+};
+
+class TestDisplayScheduler : public DisplayScheduler {
+ public:
+ TestDisplayScheduler(DisplaySchedulerClient* client,
+ BeginFrameSource* begin_frame_source,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ int max_pending_swaps)
+ : DisplayScheduler(client,
+ begin_frame_source,
+ task_runner,
+ max_pending_swaps),
+ scheduler_begin_frame_deadline_count_(0) {}
+
+ base::TimeTicks DesiredBeginFrameDeadlineTimeForTest() {
+ return DesiredBeginFrameDeadlineTime();
+ }
+
+ void BeginFrameDeadlineForTest() { OnBeginFrameDeadline(); }
+
+ void ScheduleBeginFrameDeadline() override {
+ scheduler_begin_frame_deadline_count_++;
+ DisplayScheduler::ScheduleBeginFrameDeadline();
+ }
+
+ int scheduler_begin_frame_deadline_count() {
+ return scheduler_begin_frame_deadline_count_;
+ }
+
+ protected:
+ int scheduler_begin_frame_deadline_count_;
+};
+
+class DisplaySchedulerTest : public testing::Test {
+ public:
+ DisplaySchedulerTest() {
+ const int max_pending_swaps = 1;
+ now_src_ = TestNowSource::Create();
+ null_task_runner_ = make_scoped_refptr(new base::NullTaskRunner);
+ client_ = make_scoped_ptr(new FakeDisplaySchedulerClient);
+ scheduler_ = make_scoped_ptr(
+ new TestDisplayScheduler(client_.get(), &fake_begin_frame_source_,
+ null_task_runner_, max_pending_swaps));
+ }
+
+ ~DisplaySchedulerTest() override {}
+
+ void SetUp() override { scheduler_->SetRootSurfaceResourcesLocked(false); }
+
+ void BeginFrameForTest() {
+ base::TimeTicks frame_time = now_src_->Now();
+ base::TimeDelta interval = BeginFrameArgs::DefaultInterval();
+ base::TimeTicks deadline = frame_time + interval -
+ BeginFrameArgs::DefaultEstimatedParentDrawTime();
+ fake_begin_frame_source_.TestOnBeginFrame(
+ BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+ interval, BeginFrameArgs::NORMAL));
+ }
+
+ protected:
+ TestNowSource& now_src() { return *now_src_; }
+ FakeDisplaySchedulerClient& client() { return *client_; }
+ DisplayScheduler& scheduler() { return *scheduler_; }
+
+ scoped_refptr<TestNowSource> now_src_;
+ scoped_refptr<base::NullTaskRunner> null_task_runner_;
+
+ FakeBeginFrameSource fake_begin_frame_source_;
+ scoped_ptr<FakeDisplaySchedulerClient> client_;
+ scoped_ptr<TestDisplayScheduler> scheduler_;
+};
+
+TEST_F(DisplaySchedulerTest, EntireDisplayDamagedDrawsImmediately) {
+ SurfaceId root_surface_id(1);
+ BeginFrameForTest();
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->EntireDisplayDamaged(root_surface_id);
+ EXPECT_GE(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+}
+
+TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
+ SurfaceId sid1(1);
+ SurfaceId sid2(2);
+
+ // Get scheduler to detect surface 1 as active by drawing
+ // two frames in a row with damage from surface 1.
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+
+ // Damage only from surface 2 (inactive) does not trigger deadline early.
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid2);
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+
+ // Damage from surface 1 triggers deadline early.
+ scheduler_->SurfaceDamaged(sid1);
+ EXPECT_GE(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->BeginFrameDeadlineForTest();
+
+ // Make both surface 1 and 2 active.
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid2);
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+
+ // Deadline doesn't trigger early until surface 1 and 2 are both damaged.
+ BeginFrameForTest();
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->SurfaceDamaged(sid1);
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->SurfaceDamaged(sid2);
+ EXPECT_GE(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->BeginFrameDeadlineForTest();
+}
+
+TEST_F(DisplaySchedulerTest, OutputSurfaceLost) {
+ SurfaceId sid1(1);
+
+ // DrawAndSwap normally.
+ BeginFrameForTest();
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ EXPECT_EQ(0, client_->draw_and_swap_count());
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+
+ // Deadline triggers immediately on OutputSurfaceLost.
+ BeginFrameForTest();
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->OutputSurfaceLost();
+ EXPECT_GE(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+
+ // Deadline does not DrawAndSwap after OutputSurfaceLost.
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+}
+
+TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) {
+ SurfaceId sid1(1);
+ base::TimeTicks late_deadline;
+
+ // DrawAndSwap normally.
+ BeginFrameForTest();
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ EXPECT_EQ(0, client_->draw_and_swap_count());
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+
+ // Deadline triggers late while root resources are locked.
+ late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval();
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid1);
+ EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->SetRootSurfaceResourcesLocked(true);
+ EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+
+ // Deadline does not DrawAndSwap while root resources are locked.
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+
+ // Deadline triggers normally when root resources are unlocked.
+ late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval();
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid1);
+ EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ scheduler_->SetRootSurfaceResourcesLocked(false);
+ EXPECT_EQ(base::TimeTicks(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+
+ EXPECT_EQ(1, client_->draw_and_swap_count());
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(2, client_->draw_and_swap_count());
+}
+
+TEST_F(DisplaySchedulerTest, DidSwapBuffers) {
+ SurfaceId sid1(1);
+ SurfaceId sid2(2);
+ base::TimeTicks late_deadline;
+
+ // Get scheduler to detect surface 1 and 2 as active.
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->SurfaceDamaged(sid2);
+ scheduler_->BeginFrameDeadlineForTest();
+ BeginFrameForTest();
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->SurfaceDamaged(sid2);
+ scheduler_->BeginFrameDeadlineForTest();
+
+ // DrawAndSwap normally.
+ BeginFrameForTest();
+ EXPECT_LT(now_src().Now(),
+ scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+ EXPECT_EQ(2, client_->draw_and_swap_count());
+ scheduler_->SurfaceDamaged(sid1);
+ scheduler_->SurfaceDamaged(sid2);
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(3, client_->draw_and_swap_count());
+ scheduler_->DidSwapBuffers();
+
+ // Deadline triggers early when swap throttled.
+ BeginFrameForTest();
+ // Damage surface 1, but not surface 2 so we avoid triggering deadline
+ // early because all surfaces are ready.
+ scheduler_->SurfaceDamaged(sid1);
+ EXPECT_EQ(scheduler_->DesiredBeginFrameDeadlineTimeForTest(),
+ base::TimeTicks());
+
+ // Don't draw and swap in deadline while swap throttled.
+ EXPECT_EQ(3, client_->draw_and_swap_count());
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(3, client_->draw_and_swap_count());
+
+ // Deadline triggers normally once not swap throttled.
+ // Damage from previous BeginFrame should cary over, so don't damage again.
+ late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval();
+ scheduler_->DidSwapBuffersComplete();
+ BeginFrameForTest();
+ EXPECT_GT(scheduler_->DesiredBeginFrameDeadlineTimeForTest(),
+ now_src().Now());
+ EXPECT_LT(scheduler_->DesiredBeginFrameDeadlineTimeForTest(), late_deadline);
+ // Still waiting for surface 2. Once it updates, deadline should trigger
+ // immediately again.
+ scheduler_->SurfaceDamaged(sid2);
+ EXPECT_EQ(scheduler_->DesiredBeginFrameDeadlineTimeForTest(),
+ base::TimeTicks());
+ // Draw and swap now that we aren't throttled.
+ EXPECT_EQ(3, client_->draw_and_swap_count());
+ scheduler_->BeginFrameDeadlineForTest();
+ EXPECT_EQ(4, client_->draw_and_swap_count());
+}
+
+// This test verfies that we try to reschedule the deadline
+// after any event that may change what deadline we want.
+TEST_F(DisplaySchedulerTest, ScheduleBeginFrameDeadline) {
+ SurfaceId root_surface_id(1);
+ SurfaceId sid1(2);
+ int count = 1;
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ BeginFrameForTest();
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ scheduler_->BeginFrameDeadlineForTest();
+ scheduler_->DidSwapBuffers();
+ BeginFrameForTest();
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ scheduler_->DidSwapBuffersComplete();
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ scheduler_->EntireDisplayDamaged(root_surface_id);
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ scheduler_->SurfaceDamaged(sid1);
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ scheduler_->SetRootSurfaceResourcesLocked(true);
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+
+ scheduler_->OutputSurfaceLost();
+ EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+}
+
+} // namespace
+} // namespace cc
« no previous file with comments | « cc/surfaces/display_scheduler.cc ('k') | cc/surfaces/display_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698