Index: cc/surfaces/surface_manager_unittest.cc |
diff --git a/cc/surfaces/surface_manager_unittest.cc b/cc/surfaces/surface_manager_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9e9ff2310fa7629543ec4df862b1ee7ba13fa3cc |
--- /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 |