| 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
|
|
|