// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/containers/flat_set.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_tick_clock.h" #include "components/viz/common/features.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/frame_index_constants.h" #include "components/viz/service/surfaces/surface.h" #include "components/viz/service/surfaces/surface_allocation_group.h" #include "components/viz/test/begin_frame_args_test.h" #include "components/viz/test/compositor_frame_helpers.h" #include "components/viz/test/fake_external_begin_frame_source.h" #include "components/viz/test/fake_surface_observer.h" #include "components/viz/test/mock_compositor_frame_sink_client.h" #include "components/viz/test/surface_id_allocator_set.h" #include "components/viz/test/test_surface_id_allocator.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" _; Eq; IsEmpty; UnorderedElementsAre; namespace viz { namespace { constexpr bool kIsRoot = …; constexpr bool kIsChildRoot = …; constexpr FrameSinkId kDisplayFrameSink(2, 0); constexpr FrameSinkId kParentFrameSink(3, 0); constexpr FrameSinkId kChildFrameSink1(65563, 0); constexpr FrameSinkId kChildFrameSink2(65564, 0); constexpr FrameSinkId kArbitraryFrameSink(1337, 7331); const uint64_t kBeginFrameSourceId = …; std::vector<SurfaceId> empty_surface_ids() { … } std::vector<SurfaceRange> empty_surface_ranges() { … } CompositorFrame MakeCompositorFrame( std::vector<SurfaceId> activation_dependencies, std::vector<SurfaceRange> referenced_surfaces, std::vector<TransferableResource> resource_list, const FrameDeadline& deadline = FrameDeadline()) { … } } // namespace class SurfaceSynchronizationTest : public testing::Test { … }; // The display root surface should have a surface reference from the top-level // root added/removed when a CompositorFrame is submitted with a new // SurfaceId. TEST_F(SurfaceSynchronizationTest, RootSurfaceReceivesReferences) { … } // The parent Surface is blocked on |child_id1| and |child_id2|. TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) { … } // The parent Surface is blocked on |child_id2| which is blocked on // |child_id3|. TEST_F(SurfaceSynchronizationTest, BlockedChain) { … } // parent_surface and child_surface1 are blocked on |child_id2|. TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) { … } // parent_surface is blocked on |child_id1|, and child_surface2 is blocked on // |child_id2| until the deadline hits. TEST_F(SurfaceSynchronizationTest, DeadlineHits) { … } // This test verifies that unlimited deadline mode works and that surfaces will // not activate until dependencies are resolved. TEST_F(SurfaceSynchronizationTest, UnlimitedDeadline) { … } // parent_surface is blocked on |child_id1| until a late BeginFrame arrives and // triggers a deadline. TEST_F(SurfaceSynchronizationTest, LateBeginFrameTriggersDeadline) { … } // This test verifies at the Surface activates once a CompositorFrame is // submitted that has no unresolved dependencies. TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) { … } // Supports testing features::OnBeginFrameAcks, which changes the expectations // of what IPCs are sent to the CompositorFrameSinkClient. When enabled // OnBeginFrame also handles ReturnResources as well as // DidReceiveCompositorFrameAck. class OnBeginFrameAcksSurfaceSynchronizationTest : public SurfaceSynchronizationTest, public testing::WithParamInterface<std::tuple<bool, bool>> { … }; OnBeginFrameAcksSurfaceSynchronizationTest:: OnBeginFrameAcksSurfaceSynchronizationTest() { … } void OnBeginFrameAcksSurfaceSynchronizationTest::SetUp() { … } // This test verifies that a pending CompositorFrame does not affect surface // references. A new surface from a child will continue to exist as a temporary // reference until the parent's frame activates. TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, OnlyActiveFramesAffectSurfaceReferences) { … } // This test verifies that we do not double count returned resources when a // CompositorFrame starts out as pending, then becomes active, and then is // replaced with another active CompositorFrame. TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) { … } // This test verifies that if a surface has both a pending and active // CompositorFrame and the pending CompositorFrame activates, replacing // the existing active CompositorFrame, then the surface reference hierarchy // will be updated allowing garbage collection of surfaces that are no longer // referenced. TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, DropStaleReferencesAfterActivation) { … } // Verifies that LatencyInfo does not get too large after multiple frame // submissions. TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) { … } // Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of // multiple surfaces. In this variation of the test, there are no pending // frames. TEST_F(SurfaceSynchronizationTest, LatencyInfoAggregation_NoUnresolvedDependencies) { … } // Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of // multiple surfaces. In this variation of the test, the older surface has both // pending and active frames and we verify that the LatencyInfo of both pending // and active frame are present in the aggregated LatencyInfo. TEST_F(SurfaceSynchronizationTest, LatencyInfoAggregation_OldSurfaceHasPendingAndActiveFrame) { … } // Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of // multiple surfaces. In this variation of the test, the newer surface has a // pending frame that becomes active after the dependency is resolved and we // make sure the LatencyInfo of the activated frame is included in the // aggregated LatencyInfo. TEST_F(SurfaceSynchronizationTest, LatencyInfoAggregation_NewSurfaceHasPendingFrame) { … } // Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of // multiple surfaces. In this variation of the test, multiple older surfaces // with pending frames exist during aggregation of an activated frame on a newer // surface. TEST_F(SurfaceSynchronizationTest, LatencyInfoAggregation_MultipleOldSurfacesWithPendingFrames) { … } // This test verifies that when a new surface is created, the LatencyInfo of the // previous surface does not get carried over into the new surface. TEST_F(SurfaceSynchronizationTest, LatencyInfoNotCarriedOver) { … } // Checks that resources and ack are sent together if possible. TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, ReturnResourcesWithAck) { … } // Verifies that arrival of a new CompositorFrame doesn't change the fact that a // surface is marked for destruction. TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, SubmitToDestroyedSurface) { … } // Verifies that if a LocalSurfaceId belonged to a surface that doesn't // exist anymore, it can not be recreated. TEST_F(SurfaceSynchronizationTest, LocalSurfaceIdIsNotReusable) { … } // This test verifies that a crash does not occur if garbage collection is // triggered during surface dependency resolution. This test triggers garbage // collection during surface resolution, by causing an activation to remove // a surface subtree from the root. Both the old subtree and the new // activated subtree refer to the same dependency. The old subtree was activated // by deadline, and the new subtree was activated by a dependency finally // resolving. TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) { … } // This test verifies that a crash does not occur if garbage collection is // triggered when a deadline forces frame activation. This test triggers garbage // collection during deadline activation by causing the activation of a display // frame to replace a previously activated display frame that was referring to // a now-unreachable surface subtree. That subtree gets garbage collected during // deadline activation. SurfaceDependencyTracker is also tracking a surface // from that subtree due to an unresolved dependency. This test verifies that // this dependency resolution does not crash. TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) { … } // This test verifies that a CompositorFrame will only blocked on embedded // surfaces but not on other retained surface IDs in the CompositorFrame. TEST_F(SurfaceSynchronizationTest, OnlyBlockOnEmbeddedSurfaces) { … } // This test verifies that a late arriving CompositorFrame activates // immediately and does not trigger a new deadline. TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) { … } // This test verifies that a late arriving CompositorFrame activates // immediately along with its subtree and does not trigger a new deadline. TEST_F(SurfaceSynchronizationTest, MultiLevelLateArrivingDependency) { … } // This test verifies that CompositorFrames submitted to a surface referenced // by a parent CompositorFrame as a fallback will be ACK'ed immediately. TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, FallbackSurfacesClosed) { … } // This test verifies that two surface subtrees have independent deadlines. TEST_F(SurfaceSynchronizationTest, IndependentDeadlines) { … } // This test verifies that a child inherits its deadline from its dependent // parent (embedder) if the deadline is shorter than child's deadline. TEST_F(SurfaceSynchronizationTest, InheritShorterDeadline) { … } // This test verifies that in case of A embedding B embedding C, if the deadline // of A is longer than the deadline of B, B's deadline is not extended. TEST_F(SurfaceSynchronizationTest, ChildDeadlineNotExtendedByInheritance) { … } // This test verifies that all surfaces within a dependency chain will // ultimately inherit the parent's shorter deadline even if the grandchild is // available before the child. TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) { … } // This test verifies that no crash occurs if a CompositorFrame activates AFTER // its FrameSink has been destroyed. TEST_F(SurfaceSynchronizationTest, FrameActivationAfterFrameSinkDestruction) { … } TEST_F(SurfaceSynchronizationTest, PreviousFrameSurfaceId) { … } TEST_F(SurfaceSynchronizationTest, FrameIndexWithPendingFrames) { … } // This test verifies that a new surface with a pending CompositorFrame gets // a temporary reference immediately, as opposed to when the surface activates. TEST_F(SurfaceSynchronizationTest, PendingSurfaceKeptAlive) { … } // Tests getting the correct active frame index. TEST_F(SurfaceSynchronizationTest, ActiveFrameIndex) { … } // This test verifies that SurfaceManager::GetLatestInFlightSurface returns // the latest child surface not yet set as a fallback by the parent. // Alternatively, it returns the fallback surface specified, if no tempoary // references to child surfaces are available. This mechanism is used by surface // synchronization to present the freshest surfaces available at aggregation // time. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurface) { … } // This test verifies that GetLatestInFlightSurface will return nullptr when the // start of the range is newer than its end, even if a surface matching the end // exists. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithInvalidSurfaceRange) { … } // This test verifies that GetLatestInFlightSurface will return the primary or // nullptr if fallback is not specified. // TODO(akaba): this would change after https://crbug.com/861769 TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithoutFallback) { … } // This test verifies that GetLatestInFlightSurface will not return null if the // fallback is garbage collected, but instead returns the latest surface older // than primary if that exists. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithGarbageFallback) { … } // This test verifies that in the case of different frame sinks // GetLatestInFlightSurface will return the latest surface in the primary's // FrameSinkId or the latest in the fallback's FrameSinkId if no surface exists // in the primary's. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceDifferentFrameSinkIds) { … } // This test verifies that GetLatestInFlightSurface will return the // primary surface ID if it is in the temporary reference queue. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceReturnPrimary) { … } // This test verifies that GetLatestInFlightSurface can use persistent // references to compute the latest surface. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceUsesPersistentReferences) { … } // This test verifies that GetLatestInFlightSurface will skip a surface if // its nonce is different. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceSkipDifferentNonce) { … } // This test verifies that if a child submits a LocalSurfaceId newer that the // parent's dependency, then the parent will drop its dependency and activate // if possible. In this version of the test, parent sequence number of the // activated surface is larger than that in the dependency, while the child // sequence number is smaller. TEST_F(SurfaceSynchronizationTest, DropDependenciesThatWillNeverArrive1) { … } // This test verifies that if a child submits a LocalSurfaceId newer that the // parent's dependency, then the parent will drop its dependency and activate // if possible. In this version of the test, parent sequence number of the // activated surface is smaller than that in the dependency, while the child // sequence number is larger. TEST_F(SurfaceSynchronizationTest, DropDependenciesThatWillNeverArrive2) { … } // This test verifies that a surface will continue to observe a child surface // until its dependency arrives. TEST_F(SurfaceSynchronizationTest, ObserveDependenciesUntilArrival) { … } // This test verifies that we don't mark the previous active surface for // destruction until the new surface activates. TEST_F(SurfaceSynchronizationTest, MarkPreviousSurfaceForDestructionAfterActivation) { … } // This test verifies that CompositorFrameSinkSupport does not refer to // a valid but non-existant |last_activated_surface_id_|. TEST_F(SurfaceSynchronizationTest, SetPreviousFrameSurfaceDoesntCrash) { … } // This test verifies that when a surface activates that has the same // FrameSinkId of the primary but its embed token doesn't match, we don't // update the references of the parent. TEST_F(SurfaceSynchronizationTest, SurfaceReferenceTracking_PrimaryEmbedTokenDoesntMatch) { … } // This test verifies that a parent referencing a SurfaceRange get updated // whenever a child surface activates inside this range. This should also update // the SurfaceReferences tree. TEST_F(SurfaceSynchronizationTest, SurfaceReferenceTracking_NewerSurfaceUpdatesReferences) { … } // This test verifies that once a frame sink become invalidated, it should // immediately unblock all pending frames depending on that sink. TEST_F(SurfaceSynchronizationTest, InvalidatedFrameSinkShouldNotBlockActivation) { … } TEST_F(SurfaceSynchronizationTest, EvictSurface) { … } // Tests that in cases where a pending-deletion surface (surface A) is // activated during anothother surface (surface B)'s deletion, we don't attempt // to delete surface A twice. TEST_F(SurfaceSynchronizationTest, SurfaceActivationDuringDeletion) { … } // This test verifies that if a surface is created with new embed token, a new // allocation group is created, and once that surface is destroyed, the // allocation group is destroyed as well. TEST_F(SurfaceSynchronizationTest, AllocationGroupCreationInitiatedBySubmitter) { … } // This test verifies that if a surface references another surface that has an // embed token that was never seen before, an allocation group will be created // for the embedded surface. TEST_F(SurfaceSynchronizationTest, AllocationGroupCreationInitiatedByEmbedder) { … } // This test verifies that if the parent embeds a SurfaceRange that has // different embed tokens at start and end, then initially both allocation // groups are created, but once the primary becomes available, the allocation // group for the fallback gets destroyed. TEST_F(SurfaceSynchronizationTest, FallbackAllocationGroupDestroyedAfterPrimaryAvailable) { … } // This test verifies that if the parent embeds a SurfaceRange that has // different embed tokens for primary and fallback and a surface already exists // in the primary's allocation group, we don't create an allocation group for // the fallback at all. TEST_F(SurfaceSynchronizationTest, FallbackAllocationGroupNotCreatedIfPrimaryAvailable) { … } // Verifies that the value of last active surface is correct after embed token // changes. https://crbug.com/967012 TEST_F(SurfaceSynchronizationTest, CheckLastActiveSurfaceAfterEmbedTokenChange) { … } // Regression test for https://crbug.com/1000868. Verify that the output of // GetLatestInFlightSurface is correct when there is a conflict between the last // surface in the group and the queried SurfaceRange. TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceConflict) { … } // Check that if two different SurfaceIds with the same embed token are // embedded, viz doesn't crash. https://crbug.com/1001143 TEST_F(SurfaceSynchronizationTest, DuplicateAllocationGroupInActivationDependencies) { … } class SurfaceSynchronizationTestMayAlwaysAckOnActivation : public SurfaceSynchronizationTest, public testing::WithParamInterface<bool> { … }; SurfaceSynchronizationTestMayAlwaysAckOnActivation:: SurfaceSynchronizationTestMayAlwaysAckOnActivation() { … } // Tests that when a new CompositorFrame for an Embedded Surface arrives, and is // not immediately ACKed, that when a CompositorFrame from its Embedder arrives // with new ActivationDependencies, that the UnACKed frame receives and ACK so // that that client can begin frame production to satistfy the new dependencies. // (https://crbug.com/1203804) TEST_P(SurfaceSynchronizationTestMayAlwaysAckOnActivation, UnAckedSurfaceArrivesBeforeNewActivationDependencies) { … } INSTANTIATE_TEST_SUITE_P(…); class SurfaceSynchronizationTestDrawImmediatelyWithActivationAck : public SurfaceSynchronizationTest { … }; // Tests that a frame activation causes acks when submitted for a frame prior to // an interactive frame or within the cooldown frames, post-interaction. TEST_F(SurfaceSynchronizationTestDrawImmediatelyWithActivationAck, AckOnSurfaceActivationDuringInteractionCooldown) { … } // Tests that when a CompositorFrame for an Embedded Surface arrives after its // Embedder has submitted new ActivationDependencies, that it is immediately // ACKed, even if normally it would not be due to damage. This way we don't have // an Embedder blocked on an unACKed frame. (https://crbug.com/1203804) TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, UnAckedOldActivationDependencyArrivesAfterNewDependencies) { … } // The first boolean parameter is whether BeginFrameAcks is enabled; // the second is whether AutoNeedsBeginFrame is enabled. INSTANTIATE_TEST_SUITE_P(…); } // namespace viz