| // Copyright 2020 The Fuchsia 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 SRC_UI_SCENIC_LIB_FLATLAND_ENGINE_TESTS_COMMON_H_ |
| #define SRC_UI_SCENIC_LIB_FLATLAND_ENGINE_TESTS_COMMON_H_ |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/async-testing/test_loop.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/async/default.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zx/eventpair.h> |
| |
| #include <limits> |
| #include <thread> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "src/lib/fsl/handles/object_info.h" |
| #include "src/lib/testing/loop_fixture/real_loop_fixture.h" |
| #include "src/ui/scenic/lib/flatland/engine/engine.h" |
| #include "src/ui/scenic/lib/flatland/engine/engine_types.h" |
| #include "src/ui/scenic/lib/flatland/flatland.h" |
| #include "src/ui/scenic/lib/flatland/global_image_data.h" |
| #include "src/ui/scenic/lib/flatland/global_matrix_data.h" |
| #include "src/ui/scenic/lib/flatland/global_topology_data.h" |
| #include "src/ui/scenic/lib/flatland/renderer/null_renderer.h" |
| #include "src/ui/scenic/lib/flatland/renderer/renderer.h" |
| #include "src/ui/scenic/lib/scheduling/frame_scheduler.h" |
| #include "src/ui/scenic/lib/scheduling/id.h" |
| |
| #include <glm/gtx/matrix_transform_2d.hpp> |
| |
| namespace flatland { |
| |
| class EngineTestBase : public gtest::RealLoopFixture { |
| public: |
| void SetUp() override { |
| gtest::RealLoopFixture::SetUp(); |
| uber_struct_system_ = std::make_shared<UberStructSystem>(); |
| link_system_ = std::make_shared<LinkSystem>(uber_struct_system_->GetNextInstanceId()); |
| async_set_default_dispatcher(dispatcher()); |
| |
| render_data_func_ = |
| [&](std::unordered_map<uint64_t, DisplayInfo> display_map) -> std::vector<RenderData> { |
| const auto snapshot = uber_struct_system_->Snapshot(); |
| const auto links = link_system_->GetResolvedTopologyLinks(); |
| const auto link_system_id = link_system_->GetInstanceId(); |
| |
| // Gather the flatland data into a vector of rectangle and image data that can be passed to |
| // either the display controller directly or to the software renderer. |
| std::vector<RenderData> image_list_per_display; |
| for (const auto& [display_id, display_info] : display_map) { |
| const auto& transform = display_info.transform; |
| const auto& pixel_scale = display_info.pixel_scale; |
| |
| const auto topology_data = GlobalTopologyData::ComputeGlobalTopologyData( |
| snapshot, links, link_system_id, transform); |
| const auto global_matrices = ComputeGlobalMatrices(topology_data.topology_vector, |
| topology_data.parent_indices, snapshot); |
| const auto [image_indices, images] = |
| ComputeGlobalImageData(topology_data.topology_vector, snapshot); |
| |
| const auto image_rectangles = |
| ComputeGlobalRectangles(SelectMatrices(global_matrices, image_indices)); |
| |
| link_system_->UpdateLinks(topology_data.topology_vector, topology_data.live_handles, |
| global_matrices, pixel_scale, snapshot); |
| |
| FX_DCHECK(image_rectangles.size() == images.size()); |
| image_list_per_display.push_back({.rectangles = std::move(image_rectangles), |
| .images = std::move(images), |
| .display_id = display_id}); |
| } |
| return image_list_per_display; |
| }; |
| } |
| |
| void TearDown() override { |
| uber_struct_system_.reset(); |
| link_system_.reset(); |
| |
| // Move the channel to a local variable which will go out of scope |
| // and close when this function returns. |
| zx::channel local(std::move(local_)); |
| gtest::RealLoopFixture::TearDown(); |
| } |
| |
| class FakeFlatlandSession { |
| public: |
| FakeFlatlandSession(const std::shared_ptr<UberStructSystem>& uber_struct_system, |
| const std::shared_ptr<LinkSystem>& link_system, EngineTestBase* harness) |
| : uber_struct_system_(uber_struct_system), |
| link_system_(link_system), |
| harness_(harness), |
| id_(uber_struct_system_->GetNextInstanceId()), |
| graph_(id_), |
| queue_(uber_struct_system_->AllocateQueueForSession(id_)) {} |
| |
| // Use the TransformGraph API to create and manage transforms and their children. |
| TransformGraph& graph() { return graph_; } |
| |
| // Returns the link_origin for this session. |
| TransformHandle GetLinkOrigin() const { |
| EXPECT_TRUE(this->parent_link_.has_value()); |
| return this->parent_link_.value().parent_link.link_origin; |
| } |
| |
| // Clears the ParentLink for this session, if one exists. |
| void ClearParentLink() { parent_link_.reset(); } |
| |
| // Holds the ContentLink and LinkSystem::ChildLink objects since if they fall out of scope, |
| // the LinkSystem will delete the link. Tests should add |child_link.link_handle| to their |
| // TransformGraphs to use the ChildLink in a topology. |
| struct ChildLink { |
| fidl::InterfacePtr<fuchsia::ui::scenic::internal::ContentLink> content_link; |
| LinkSystem::ChildLink child_link; |
| |
| // Returns the handle the parent should add as a child in its local topology to include the |
| // link in the topology. |
| TransformHandle GetLinkHandle() const { return child_link.link_handle; } |
| }; |
| |
| // Links this session to |parent_session| and returns the ChildLink, which should be used with |
| // the parent session. If the return value drops out of scope, tests should call |
| // ClearParentLink() on this session. |
| ChildLink LinkToParent(FakeFlatlandSession& parent_session); |
| |
| // Allocates a new UberStruct with a local_topology rooted at |local_root|. If this session has |
| // a ParentLink, the link_origin of that ParentLink will be used instead. |
| std::unique_ptr<UberStruct> CreateUberStructWithCurrentTopology(TransformHandle local_root); |
| |
| // Pushes |uber_struct| to the UberStructSystem and updates the system so that it represents |
| // this session in the InstanceMap. |
| void PushUberStruct(std::unique_ptr<UberStruct> uber_struct); |
| |
| private: |
| // Shared systems for all sessions. |
| std::shared_ptr<UberStructSystem> uber_struct_system_; |
| std::shared_ptr<LinkSystem> link_system_; |
| |
| // The test harness to give access to RunLoopUntilIdle(). |
| EngineTestBase* harness_; |
| |
| // Data specific to this session. |
| scheduling::SessionId id_; |
| TransformGraph graph_; |
| std::shared_ptr<UberStructSystem::UberStructQueue> queue_; |
| |
| // Holds the GraphLink and LinkSystem::ParentLink objects since if they fall out of scope, |
| // the LinkSystem will delete the link. When |parent_link_| has a value, the |
| // |parent_link.link_origin| from this object is used as the root TransformHandle. |
| struct ParentLink { |
| fidl::InterfacePtr<fuchsia::ui::scenic::internal::GraphLink> graph_link; |
| LinkSystem::ParentLink parent_link; |
| }; |
| std::optional<ParentLink> parent_link_; |
| }; |
| |
| FakeFlatlandSession CreateSession() { |
| return FakeFlatlandSession(uber_struct_system_, link_system_, this); |
| } |
| |
| protected: |
| const std::shared_ptr<UberStructSystem>& uber_struct_system() const { |
| return uber_struct_system_; |
| } |
| |
| const std::shared_ptr<LinkSystem>& link_system() const { return link_system_; } |
| |
| RenderDataFunc render_data_func() { return render_data_func_; } |
| |
| private: |
| // Systems that are populated with data from Flatland instances. |
| std::shared_ptr<UberStructSystem> uber_struct_system_; |
| std::shared_ptr<LinkSystem> link_system_; |
| RenderDataFunc render_data_func_; |
| zx::channel local_; |
| }; |
| |
| } // namespace flatland |
| |
| #endif // SRC_UI_SCENIC_LIB_FLATLAND_ENGINE_TESTS_COMMON_H_ |