summaryrefslogtreecommitdiffstats
path: root/cc/surfaces/surface_manager_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cc/surfaces/surface_manager_unittest.cc')
-rw-r--r--cc/surfaces/surface_manager_unittest.cc382
1 files changed, 382 insertions, 0 deletions
diff --git a/cc/surfaces/surface_manager_unittest.cc b/cc/surfaces/surface_manager_unittest.cc
new file mode 100644
index 0000000..9e9ff23
--- /dev/null
+++ b/cc/surfaces/surface_manager_unittest.cc
@@ -0,0 +1,382 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+class FakeSurfaceFactoryClient : public SurfaceFactoryClient {
+ public:
+ explicit FakeSurfaceFactoryClient(int id_namespace)
+ : source_(nullptr), manager_(nullptr), id_namespace_(id_namespace) {}
+ FakeSurfaceFactoryClient(int id_namespace, SurfaceManager* manager)
+ : source_(nullptr), manager_(nullptr), id_namespace_(id_namespace) {
+ DCHECK(manager);
+ Register(manager);
+ }
+
+ ~FakeSurfaceFactoryClient() override {
+ if (manager_) {
+ Unregister();
+ }
+ EXPECT_EQ(source_, nullptr);
+ }
+
+ BeginFrameSource* source() { return source_; }
+ uint32_t id_namespace() { return id_namespace_; }
+
+ void Register(SurfaceManager* manager) {
+ EXPECT_EQ(manager_, nullptr);
+ manager_ = manager;
+ manager_->RegisterSurfaceFactoryClient(id_namespace_, this);
+ }
+
+ void Unregister() {
+ EXPECT_NE(manager_, nullptr);
+ manager_->UnregisterSurfaceFactoryClient(id_namespace_);
+ manager_ = nullptr;
+ }
+
+ // SurfaceFactoryClient implementation.
+ void ReturnResources(const ReturnedResourceArray& resources) override{};
+ void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {
+ DCHECK(!source_ || !begin_frame_source);
+ source_ = begin_frame_source;
+ };
+
+ private:
+ BeginFrameSource* source_;
+ SurfaceManager* manager_;
+ uint32_t id_namespace_;
+};
+
+class EmptyBeginFrameSource : public BeginFrameSource {
+ public:
+ void DidFinishFrame(size_t remaining_frames) override{};
+ void AddObserver(BeginFrameObserver* obs) override{};
+ void RemoveObserver(BeginFrameObserver* obs) override{};
+ void SetClientReady() override {}
+ void AsValueInto(base::trace_event::TracedValue* dict) const override{};
+};
+
+class SurfaceManagerTest : public testing::Test {
+ public:
+ // These tests don't care about namespace registration, so just preregister
+ // a set of namespaces that tests can use freely without worrying if they're
+ // valid or not.
+ enum { MAX_NAMESPACE = 10 };
+
+ SurfaceManagerTest() {
+ for (size_t i = 0; i < MAX_NAMESPACE; ++i)
+ manager_.RegisterSurfaceIdNamespace(i);
+ }
+
+ ~SurfaceManagerTest() override {
+ for (size_t i = 0; i < MAX_NAMESPACE; ++i)
+ manager_.InvalidateSurfaceIdNamespace(i);
+ }
+
+ protected:
+ SurfaceManager manager_;
+};
+
+TEST_F(SurfaceManagerTest, SingleClients) {
+ FakeSurfaceFactoryClient client(1);
+ FakeSurfaceFactoryClient other_client(2);
+ EmptyBeginFrameSource source;
+
+ EXPECT_EQ(client.source(), nullptr);
+ EXPECT_EQ(other_client.source(), nullptr);
+ client.Register(&manager_);
+ other_client.Register(&manager_);
+ EXPECT_EQ(client.source(), nullptr);
+ EXPECT_EQ(other_client.source(), nullptr);
+
+ // Test setting unsetting BFS
+ manager_.RegisterBeginFrameSource(&source, client.id_namespace());
+ EXPECT_EQ(client.source(), &source);
+ EXPECT_EQ(other_client.source(), nullptr);
+ manager_.UnregisterBeginFrameSource(&source);
+ EXPECT_EQ(client.source(), nullptr);
+ EXPECT_EQ(other_client.source(), nullptr);
+
+ // Set BFS for other namespace
+ manager_.RegisterBeginFrameSource(&source, other_client.id_namespace());
+ EXPECT_EQ(other_client.source(), &source);
+ EXPECT_EQ(client.source(), nullptr);
+ manager_.UnregisterBeginFrameSource(&source);
+ EXPECT_EQ(client.source(), nullptr);
+ EXPECT_EQ(other_client.source(), nullptr);
+
+ // Re-set BFS for original
+ manager_.RegisterBeginFrameSource(&source, client.id_namespace());
+ EXPECT_EQ(client.source(), &source);
+ manager_.UnregisterBeginFrameSource(&source);
+ EXPECT_EQ(client.source(), nullptr);
+}
+
+TEST_F(SurfaceManagerTest, MultipleDisplays) {
+ EmptyBeginFrameSource root1_source;
+ EmptyBeginFrameSource root2_source;
+
+ // root1 -> A -> B
+ // root2 -> C
+ FakeSurfaceFactoryClient root1(1, &manager_);
+ FakeSurfaceFactoryClient root2(2, &manager_);
+ FakeSurfaceFactoryClient client_a(3, &manager_);
+ FakeSurfaceFactoryClient client_b(4, &manager_);
+ FakeSurfaceFactoryClient client_c(5, &manager_);
+
+ manager_.RegisterBeginFrameSource(&root1_source, root1.id_namespace());
+ manager_.RegisterBeginFrameSource(&root2_source, root2.id_namespace());
+ EXPECT_EQ(root1.source(), &root1_source);
+ EXPECT_EQ(root2.source(), &root2_source);
+
+ // Set up initial hierarchy.
+ manager_.RegisterSurfaceNamespaceHierarchy(root1.id_namespace(),
+ client_a.id_namespace());
+ EXPECT_EQ(client_a.source(), root1.source());
+ manager_.RegisterSurfaceNamespaceHierarchy(client_a.id_namespace(),
+ client_b.id_namespace());
+ EXPECT_EQ(client_b.source(), root1.source());
+ manager_.RegisterSurfaceNamespaceHierarchy(root2.id_namespace(),
+ client_c.id_namespace());
+ EXPECT_EQ(client_c.source(), root2.source());
+
+ // Attach A into root2's subtree, like a window moving across displays.
+ // root1 -> A -> B
+ // root2 -> C -> A -> B
+ manager_.RegisterSurfaceNamespaceHierarchy(client_c.id_namespace(),
+ client_a.id_namespace());
+ // With the heuristic of just keeping existing BFS in the face of multiple,
+ // no client sources should change.
+ EXPECT_EQ(client_a.source(), root1.source());
+ EXPECT_EQ(client_b.source(), root1.source());
+ EXPECT_EQ(client_c.source(), root2.source());
+
+ // Detach A from root1. A and B should now be updated to root2.
+ manager_.UnregisterSurfaceNamespaceHierarchy(root1.id_namespace(),
+ client_a.id_namespace());
+ EXPECT_EQ(client_a.source(), root2.source());
+ EXPECT_EQ(client_b.source(), root2.source());
+ EXPECT_EQ(client_c.source(), root2.source());
+
+ // Detach root1 from BFS. root1 should now have no source.
+ manager_.UnregisterBeginFrameSource(&root1_source);
+ EXPECT_EQ(root1.source(), nullptr);
+ EXPECT_NE(root2.source(), nullptr);
+
+ // Detatch root2 from BFS.
+ manager_.UnregisterBeginFrameSource(&root2_source);
+ EXPECT_EQ(client_a.source(), nullptr);
+ EXPECT_EQ(client_b.source(), nullptr);
+ EXPECT_EQ(client_c.source(), nullptr);
+ EXPECT_EQ(root2.source(), nullptr);
+
+ // Cleanup hierarchy.
+ manager_.UnregisterSurfaceNamespaceHierarchy(root2.id_namespace(),
+ client_c.id_namespace());
+ manager_.UnregisterSurfaceNamespaceHierarchy(client_c.id_namespace(),
+ client_a.id_namespace());
+ manager_.UnregisterSurfaceNamespaceHierarchy(client_a.id_namespace(),
+ client_b.id_namespace());
+}
+
+// In practice, registering and unregistering both parent/child relationships
+// and SurfaceFactoryClients can happen in any ordering with respect to
+// each other. These following tests verify that all the data structures
+// are properly set up and cleaned up under the four permutations of orderings
+// of this nesting.
+
+class SurfaceManagerOrderingTest : public SurfaceManagerTest {
+ public:
+ SurfaceManagerOrderingTest()
+ : client_a_(1),
+ client_b_(2),
+ client_c_(3),
+ hierarchy_registered_(false),
+ clients_registered_(false),
+ bfs_registered_(false) {
+ AssertCorrectBFSState();
+ }
+
+ ~SurfaceManagerOrderingTest() override {
+ EXPECT_EQ(hierarchy_registered_, false);
+ EXPECT_EQ(clients_registered_, false);
+ EXPECT_EQ(bfs_registered_, false);
+ AssertCorrectBFSState();
+ }
+
+ void RegisterHierarchy() {
+ DCHECK(!hierarchy_registered_);
+ hierarchy_registered_ = true;
+ manager_.RegisterSurfaceNamespaceHierarchy(client_a_.id_namespace(),
+ client_b_.id_namespace());
+ manager_.RegisterSurfaceNamespaceHierarchy(client_b_.id_namespace(),
+ client_c_.id_namespace());
+ AssertCorrectBFSState();
+ }
+ void UnregisterHierarchy() {
+ DCHECK(hierarchy_registered_);
+ hierarchy_registered_ = false;
+ manager_.UnregisterSurfaceNamespaceHierarchy(client_a_.id_namespace(),
+ client_b_.id_namespace());
+ manager_.UnregisterSurfaceNamespaceHierarchy(client_b_.id_namespace(),
+ client_c_.id_namespace());
+ AssertCorrectBFSState();
+ }
+
+ void RegisterClients() {
+ DCHECK(!clients_registered_);
+ clients_registered_ = true;
+ client_a_.Register(&manager_);
+ client_b_.Register(&manager_);
+ client_c_.Register(&manager_);
+ AssertCorrectBFSState();
+ }
+
+ void UnregisterClients() {
+ DCHECK(clients_registered_);
+ clients_registered_ = false;
+ client_a_.Unregister();
+ client_b_.Unregister();
+ client_c_.Unregister();
+ AssertCorrectBFSState();
+ }
+
+ void RegisterBFS() {
+ DCHECK(!bfs_registered_);
+ bfs_registered_ = true;
+ manager_.RegisterBeginFrameSource(&source_, client_a_.id_namespace());
+ AssertCorrectBFSState();
+ }
+ void UnregisterBFS() {
+ DCHECK(bfs_registered_);
+ bfs_registered_ = false;
+ manager_.UnregisterBeginFrameSource(&source_);
+ AssertCorrectBFSState();
+ }
+
+ void AssertEmptyBFS() {
+ EXPECT_EQ(client_a_.source(), nullptr);
+ EXPECT_EQ(client_b_.source(), nullptr);
+ EXPECT_EQ(client_c_.source(), nullptr);
+ }
+
+ void AssertAllValidBFS() {
+ EXPECT_EQ(client_a_.source(), &source_);
+ EXPECT_EQ(client_b_.source(), &source_);
+ EXPECT_EQ(client_c_.source(), &source_);
+ }
+
+ protected:
+ void AssertCorrectBFSState() {
+ if (!clients_registered_ || !bfs_registered_) {
+ AssertEmptyBFS();
+ return;
+ }
+ if (!hierarchy_registered_) {
+ // A valid but not attached to anything.
+ EXPECT_EQ(client_a_.source(), &source_);
+ EXPECT_EQ(client_b_.source(), nullptr);
+ EXPECT_EQ(client_c_.source(), nullptr);
+ return;
+ }
+
+ AssertAllValidBFS();
+ }
+
+ EmptyBeginFrameSource source_;
+ // A -> B -> C hierarchy, with A always having the BFS.
+ FakeSurfaceFactoryClient client_a_;
+ FakeSurfaceFactoryClient client_b_;
+ FakeSurfaceFactoryClient client_c_;
+
+ bool hierarchy_registered_;
+ bool clients_registered_;
+ bool bfs_registered_;
+};
+
+enum RegisterOrder { REGISTER_HIERARCHY_FIRST, REGISTER_CLIENTS_FIRST };
+enum UnregisterOrder { UNREGISTER_HIERARCHY_FIRST, UNREGISTER_CLIENTS_FIRST };
+enum BFSOrder { BFS_FIRST, BFS_SECOND, BFS_THIRD };
+
+static const RegisterOrder kRegisterOrderList[] = {REGISTER_HIERARCHY_FIRST,
+ REGISTER_CLIENTS_FIRST};
+static const UnregisterOrder kUnregisterOrderList[] = {
+ UNREGISTER_HIERARCHY_FIRST, UNREGISTER_CLIENTS_FIRST};
+static const BFSOrder kBFSOrderList[] = {BFS_FIRST, BFS_SECOND, BFS_THIRD};
+
+class SurfaceManagerOrderingParamTest
+ : public SurfaceManagerOrderingTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<RegisterOrder, UnregisterOrder, BFSOrder>> {};
+
+TEST_P(SurfaceManagerOrderingParamTest, Ordering) {
+ // Test the four permutations of client/hierarchy setting/unsetting and test
+ // each place the BFS can be added and removed. The BFS and the
+ // client/hierarchy are less related, so BFS is tested independently instead
+ // of every permutation of BFS setting and unsetting.
+ // The register/unregister functions themselves test most of the state.
+ RegisterOrder register_order = std::tr1::get<0>(GetParam());
+ UnregisterOrder unregister_order = std::tr1::get<1>(GetParam());
+ BFSOrder bfs_order = std::tr1::get<2>(GetParam());
+
+ // Attach everything up in the specified order.
+ if (bfs_order == BFS_FIRST)
+ RegisterBFS();
+
+ if (register_order == REGISTER_HIERARCHY_FIRST)
+ RegisterHierarchy();
+ else
+ RegisterClients();
+
+ if (bfs_order == BFS_SECOND)
+ RegisterBFS();
+
+ if (register_order == REGISTER_HIERARCHY_FIRST)
+ RegisterClients();
+ else
+ RegisterHierarchy();
+
+ if (bfs_order == BFS_THIRD)
+ RegisterBFS();
+
+ // Everything hooked up, so should be valid.
+ AssertAllValidBFS();
+
+ // Detach everything in the specified order.
+ if (bfs_order == BFS_THIRD)
+ UnregisterBFS();
+
+ if (unregister_order == UNREGISTER_HIERARCHY_FIRST)
+ UnregisterHierarchy();
+ else
+ UnregisterClients();
+
+ if (bfs_order == BFS_SECOND)
+ UnregisterBFS();
+
+ if (unregister_order == UNREGISTER_HIERARCHY_FIRST)
+ UnregisterClients();
+ else
+ UnregisterHierarchy();
+
+ if (bfs_order == BFS_FIRST)
+ UnregisterBFS();
+}
+
+INSTANTIATE_TEST_CASE_P(
+ SurfaceManagerOrderingParamTestInstantiation,
+ SurfaceManagerOrderingParamTest,
+ ::testing::Combine(::testing::ValuesIn(kRegisterOrderList),
+ ::testing::ValuesIn(kUnregisterOrderList),
+ ::testing::ValuesIn(kBFSOrderList)));
+
+} // namespace cc